blob: 20fdf8cceae97c375665a8bc4377319863a7129a [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 Purdie6c77fd62008-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;
Boris Brezillond30aae62016-02-03 20:12:31 +01001027 int ret;
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001028
Boris Brezillond30aae62016-02-03 20:12:31 +01001029 this->read_bufferram(mtd, ONENAND_SPARERAM, this->oob_buf, 0,
1030 mtd->oobsize);
1031 ret = mtd_ooblayout_get_databytes(mtd, buf, this->oob_buf,
1032 column, thislen);
1033 if (ret)
1034 return ret;
1035
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001036 return 0;
1037}
1038
1039/**
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001040 * onenand_recover_lsb - [Flex-OneNAND] Recover LSB page data
1041 * @param mtd MTD device structure
1042 * @param addr address to recover
1043 * @param status return value from onenand_wait / onenand_bbt_wait
1044 *
1045 * MLC NAND Flash cell has paired pages - LSB page and MSB page. LSB page has
1046 * lower page address and MSB page has higher page address in paired pages.
1047 * If power off occurs during MSB page program, the paired LSB page data can
1048 * become corrupt. LSB page recovery read is a way to read LSB page though page
1049 * data are corrupted. When uncorrectable error occurs as a result of LSB page
1050 * read after power up, issue LSB page recovery read.
1051 */
1052static int onenand_recover_lsb(struct mtd_info *mtd, loff_t addr, int status)
1053{
1054 struct onenand_chip *this = mtd->priv;
1055 int i;
1056
1057 /* Recovery is only for Flex-OneNAND */
1058 if (!FLEXONENAND(this))
1059 return status;
1060
1061 /* check if we failed due to uncorrectable error */
Brian Norrisd57f40542011-09-20 18:34:25 -07001062 if (!mtd_is_eccerr(status) && status != ONENAND_BBT_READ_ECC_ERROR)
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001063 return status;
1064
1065 /* check if address lies in MLC region */
1066 i = flexonenand_region(mtd, addr);
1067 if (mtd->eraseregions[i].erasesize < (1 << this->erase_shift))
1068 return status;
1069
1070 /* We are attempting to reread, so decrement stats.failed
1071 * which was incremented by onenand_wait due to read failure
1072 */
Amul Kumar Saha297758f2009-10-02 16:59:11 +05301073 printk(KERN_INFO "%s: Attempting to recover from uncorrectable read\n",
1074 __func__);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001075 mtd->ecc_stats.failed--;
1076
1077 /* Issue the LSB page recovery command */
1078 this->command(mtd, FLEXONENAND_CMD_RECOVER_LSB, addr, this->writesize);
1079 return this->wait(mtd, FL_READING);
1080}
1081
1082/**
1083 * onenand_mlc_read_ops_nolock - MLC OneNAND read main and/or out-of-band
1084 * @param mtd MTD device structure
1085 * @param from offset to read from
1086 * @param ops: oob operation description structure
1087 *
1088 * MLC OneNAND / Flex-OneNAND has 4KB page size and 4KB dataram.
1089 * So, read-while-load is not present.
1090 */
1091static int onenand_mlc_read_ops_nolock(struct mtd_info *mtd, loff_t from,
1092 struct mtd_oob_ops *ops)
1093{
1094 struct onenand_chip *this = mtd->priv;
1095 struct mtd_ecc_stats stats;
1096 size_t len = ops->len;
1097 size_t ooblen = ops->ooblen;
1098 u_char *buf = ops->datbuf;
1099 u_char *oobbuf = ops->oobbuf;
1100 int read = 0, column, thislen;
1101 int oobread = 0, oobcolumn, thisooblen, oobsize;
1102 int ret = 0;
1103 int writesize = this->writesize;
1104
Brian Norris0a32a102011-07-19 10:06:10 -07001105 pr_debug("%s: from = 0x%08x, len = %i\n", __func__, (unsigned int)from,
1106 (int)len);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001107
Boris BREZILLON29f10582016-03-07 10:46:52 +01001108 oobsize = mtd_oobavail(mtd, ops);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001109 oobcolumn = from & (mtd->oobsize - 1);
1110
1111 /* Do not allow reads past end of device */
1112 if (from + len > mtd->size) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05301113 printk(KERN_ERR "%s: Attempt read beyond end of device\n",
1114 __func__);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001115 ops->retlen = 0;
1116 ops->oobretlen = 0;
1117 return -EINVAL;
1118 }
1119
1120 stats = mtd->ecc_stats;
1121
1122 while (read < len) {
1123 cond_resched();
1124
1125 thislen = min_t(int, writesize, len - read);
1126
1127 column = from & (writesize - 1);
1128 if (column + thislen > writesize)
1129 thislen = writesize - column;
1130
1131 if (!onenand_check_bufferram(mtd, from)) {
1132 this->command(mtd, ONENAND_CMD_READ, from, writesize);
1133
1134 ret = this->wait(mtd, FL_READING);
1135 if (unlikely(ret))
1136 ret = onenand_recover_lsb(mtd, from, ret);
1137 onenand_update_bufferram(mtd, from, !ret);
Brian Norrisd57f40542011-09-20 18:34:25 -07001138 if (mtd_is_eccerr(ret))
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001139 ret = 0;
Adrian Hunterb0850582011-02-08 12:02:38 +02001140 if (ret)
1141 break;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001142 }
1143
1144 this->read_bufferram(mtd, ONENAND_DATARAM, buf, column, thislen);
1145 if (oobbuf) {
1146 thisooblen = oobsize - oobcolumn;
1147 thisooblen = min_t(int, thisooblen, ooblen - oobread);
1148
Brian Norris0612b9d2011-08-30 18:45:40 -07001149 if (ops->mode == MTD_OPS_AUTO_OOB)
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001150 onenand_transfer_auto_oob(mtd, oobbuf, oobcolumn, thisooblen);
1151 else
1152 this->read_bufferram(mtd, ONENAND_SPARERAM, oobbuf, oobcolumn, thisooblen);
1153 oobread += thisooblen;
1154 oobbuf += thisooblen;
1155 oobcolumn = 0;
1156 }
1157
1158 read += thislen;
1159 if (read == len)
1160 break;
1161
1162 from += thislen;
1163 buf += thislen;
1164 }
1165
1166 /*
1167 * Return success, if no ECC failures, else -EBADMSG
1168 * fs driver will take care of that, because
1169 * retlen == desired len and result == -EBADMSG
1170 */
1171 ops->retlen = read;
1172 ops->oobretlen = oobread;
1173
1174 if (ret)
1175 return ret;
1176
1177 if (mtd->ecc_stats.failed - stats.failed)
1178 return -EBADMSG;
1179
Mike Dunnedbc45402012-04-25 12:06:11 -07001180 /* return max bitflips per ecc step; ONENANDs correct 1 bit only */
1181 return mtd->ecc_stats.corrected != stats.corrected ? 1 : 0;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001182}
1183
1184/**
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03001185 * onenand_read_ops_nolock - [OneNAND Interface] OneNAND read main and/or out-of-band
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001186 * @param mtd MTD device structure
1187 * @param from offset to read from
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001188 * @param ops: oob operation description structure
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001189 *
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001190 * OneNAND read main and/or out-of-band data
1191 */
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03001192static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001193 struct mtd_oob_ops *ops)
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001194{
1195 struct onenand_chip *this = mtd->priv;
Kyungmin Parkf4f91ac2006-11-16 12:03:56 +09001196 struct mtd_ecc_stats stats;
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001197 size_t len = ops->len;
1198 size_t ooblen = ops->ooblen;
1199 u_char *buf = ops->datbuf;
1200 u_char *oobbuf = ops->oobbuf;
1201 int read = 0, column, thislen;
1202 int oobread = 0, oobcolumn, thisooblen, oobsize;
Adrian Hunter0fc2cce2007-01-09 17:55:21 +02001203 int ret = 0, boundary = 0;
Kyungmin Parkee9745f2007-06-30 13:57:49 +09001204 int writesize = this->writesize;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001205
Brian Norris0a32a102011-07-19 10:06:10 -07001206 pr_debug("%s: from = 0x%08x, len = %i\n", __func__, (unsigned int)from,
1207 (int)len);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001208
Boris BREZILLON29f10582016-03-07 10:46:52 +01001209 oobsize = mtd_oobavail(mtd, ops);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001210 oobcolumn = from & (mtd->oobsize - 1);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001211
1212 /* Do not allow reads past end of device */
1213 if ((from + len) > mtd->size) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05301214 printk(KERN_ERR "%s: Attempt read beyond end of device\n",
1215 __func__);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001216 ops->retlen = 0;
1217 ops->oobretlen = 0;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001218 return -EINVAL;
1219 }
1220
Kyungmin Parkf4f91ac2006-11-16 12:03:56 +09001221 stats = mtd->ecc_stats;
Artem Bityutskiy61a7e192006-12-26 16:41:24 +09001222
Adrian Huntera8de85d2007-01-04 09:51:26 +02001223 /* Read-while-load method */
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001224
Adrian Huntera8de85d2007-01-04 09:51:26 +02001225 /* Do first load to bufferRAM */
1226 if (read < len) {
1227 if (!onenand_check_bufferram(mtd, from)) {
Kyungmin Parkee9745f2007-06-30 13:57:49 +09001228 this->command(mtd, ONENAND_CMD_READ, from, writesize);
Adrian Huntera8de85d2007-01-04 09:51:26 +02001229 ret = this->wait(mtd, FL_READING);
1230 onenand_update_bufferram(mtd, from, !ret);
Brian Norrisd57f40542011-09-20 18:34:25 -07001231 if (mtd_is_eccerr(ret))
Adrian Hunter5f4d47d2007-11-06 09:17:25 +02001232 ret = 0;
Adrian Huntera8de85d2007-01-04 09:51:26 +02001233 }
1234 }
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001235
Kyungmin Parkee9745f2007-06-30 13:57:49 +09001236 thislen = min_t(int, writesize, len - read);
1237 column = from & (writesize - 1);
1238 if (column + thislen > writesize)
1239 thislen = writesize - column;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001240
Adrian Huntera8de85d2007-01-04 09:51:26 +02001241 while (!ret) {
1242 /* If there is more to load then start next load */
1243 from += thislen;
1244 if (read + thislen < len) {
Kyungmin Parkee9745f2007-06-30 13:57:49 +09001245 this->command(mtd, ONENAND_CMD_READ, from, writesize);
Adrian Hunter0fc2cce2007-01-09 17:55:21 +02001246 /*
1247 * Chip boundary handling in DDP
1248 * Now we issued chip 1 read and pointed chip 1
Mika Korhonen492e1502009-06-09 21:52:35 +03001249 * bufferram so we have to point chip 0 bufferram.
Adrian Hunter0fc2cce2007-01-09 17:55:21 +02001250 */
Kyungmin Park738d61f2007-01-15 17:09:14 +09001251 if (ONENAND_IS_DDP(this) &&
1252 unlikely(from == (this->chipsize >> 1))) {
1253 this->write_word(ONENAND_DDP_CHIP0, this->base + ONENAND_REG_START_ADDRESS2);
Adrian Hunter0fc2cce2007-01-09 17:55:21 +02001254 boundary = 1;
1255 } else
1256 boundary = 0;
Adrian Huntera8de85d2007-01-04 09:51:26 +02001257 ONENAND_SET_PREV_BUFFERRAM(this);
1258 }
1259 /* While load is going, read from last bufferRAM */
1260 this->read_bufferram(mtd, ONENAND_DATARAM, buf, column, thislen);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001261
1262 /* Read oob area if needed */
1263 if (oobbuf) {
1264 thisooblen = oobsize - oobcolumn;
1265 thisooblen = min_t(int, thisooblen, ooblen - oobread);
1266
Brian Norris0612b9d2011-08-30 18:45:40 -07001267 if (ops->mode == MTD_OPS_AUTO_OOB)
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001268 onenand_transfer_auto_oob(mtd, oobbuf, oobcolumn, thisooblen);
1269 else
1270 this->read_bufferram(mtd, ONENAND_SPARERAM, oobbuf, oobcolumn, thisooblen);
1271 oobread += thisooblen;
1272 oobbuf += thisooblen;
1273 oobcolumn = 0;
1274 }
1275
Adrian Huntera8de85d2007-01-04 09:51:26 +02001276 /* See if we are done */
1277 read += thislen;
1278 if (read == len)
1279 break;
1280 /* Set up for next read from bufferRAM */
Adrian Hunter0fc2cce2007-01-09 17:55:21 +02001281 if (unlikely(boundary))
Kyungmin Park738d61f2007-01-15 17:09:14 +09001282 this->write_word(ONENAND_DDP_CHIP1, this->base + ONENAND_REG_START_ADDRESS2);
Adrian Huntera8de85d2007-01-04 09:51:26 +02001283 ONENAND_SET_NEXT_BUFFERRAM(this);
1284 buf += thislen;
Kyungmin Parkee9745f2007-06-30 13:57:49 +09001285 thislen = min_t(int, writesize, len - read);
Adrian Huntera8de85d2007-01-04 09:51:26 +02001286 column = 0;
1287 cond_resched();
1288 /* Now wait for load */
1289 ret = this->wait(mtd, FL_READING);
1290 onenand_update_bufferram(mtd, from, !ret);
Brian Norrisd57f40542011-09-20 18:34:25 -07001291 if (mtd_is_eccerr(ret))
Adrian Hunter5f4d47d2007-11-06 09:17:25 +02001292 ret = 0;
Adrian Huntera8de85d2007-01-04 09:51:26 +02001293 }
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001294
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001295 /*
1296 * Return success, if no ECC failures, else -EBADMSG
1297 * fs driver will take care of that, because
1298 * retlen == desired len and result == -EBADMSG
1299 */
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001300 ops->retlen = read;
1301 ops->oobretlen = oobread;
Kyungmin Parkf4f91ac2006-11-16 12:03:56 +09001302
Adrian Huntera8de85d2007-01-04 09:51:26 +02001303 if (ret)
1304 return ret;
1305
Adrian Hunter5f4d47d2007-11-06 09:17:25 +02001306 if (mtd->ecc_stats.failed - stats.failed)
1307 return -EBADMSG;
1308
Mike Dunnedbc45402012-04-25 12:06:11 -07001309 /* return max bitflips per ecc step; ONENANDs correct 1 bit only */
1310 return mtd->ecc_stats.corrected != stats.corrected ? 1 : 0;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001311}
1312
1313/**
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03001314 * onenand_read_oob_nolock - [MTD Interface] OneNAND read out-of-band
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001315 * @param mtd MTD device structure
1316 * @param from offset to read from
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001317 * @param ops: oob operation description structure
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001318 *
1319 * OneNAND read out-of-band data from the spare area
1320 */
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03001321static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from,
Kyungmin Park12f77c92007-08-30 09:36:05 +09001322 struct mtd_oob_ops *ops)
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001323{
1324 struct onenand_chip *this = mtd->priv;
Adrian Hunter5f4d47d2007-11-06 09:17:25 +02001325 struct mtd_ecc_stats stats;
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02001326 int read = 0, thislen, column, oobsize;
Kyungmin Park12f77c92007-08-30 09:36:05 +09001327 size_t len = ops->ooblen;
Brian Norris905c6bc2011-08-30 18:45:39 -07001328 unsigned int mode = ops->mode;
Kyungmin Park12f77c92007-08-30 09:36:05 +09001329 u_char *buf = ops->oobbuf;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001330 int ret = 0, readcmd;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001331
Kyungmin Park12f77c92007-08-30 09:36:05 +09001332 from += ops->ooboffs;
1333
Brian Norris0a32a102011-07-19 10:06:10 -07001334 pr_debug("%s: from = 0x%08x, len = %i\n", __func__, (unsigned int)from,
1335 (int)len);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001336
1337 /* Initialize return length value */
Kyungmin Park12f77c92007-08-30 09:36:05 +09001338 ops->oobretlen = 0;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001339
Brian Norris0612b9d2011-08-30 18:45:40 -07001340 if (mode == MTD_OPS_AUTO_OOB)
Boris BREZILLONf5b8aa72016-03-07 10:46:51 +01001341 oobsize = mtd->oobavail;
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02001342 else
1343 oobsize = mtd->oobsize;
1344
1345 column = from & (mtd->oobsize - 1);
1346
1347 if (unlikely(column >= oobsize)) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05301348 printk(KERN_ERR "%s: Attempted to start read outside oob\n",
1349 __func__);
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02001350 return -EINVAL;
1351 }
1352
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001353 /* Do not allow reads past end of device */
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02001354 if (unlikely(from >= mtd->size ||
1355 column + len > ((mtd->size >> this->page_shift) -
1356 (from >> this->page_shift)) * oobsize)) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05301357 printk(KERN_ERR "%s: Attempted to read beyond end of device\n",
1358 __func__);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001359 return -EINVAL;
1360 }
1361
Adrian Hunter5f4d47d2007-11-06 09:17:25 +02001362 stats = mtd->ecc_stats;
1363
Kyungmin Park8a8f6322010-12-02 09:24:16 +09001364 readcmd = ONENAND_IS_4KB_PAGE(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001365
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001366 while (read < len) {
Artem Bityutskiy61a7e192006-12-26 16:41:24 +09001367 cond_resched();
1368
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02001369 thislen = oobsize - column;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001370 thislen = min_t(int, thislen, len);
1371
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001372 this->command(mtd, readcmd, from, mtd->oobsize);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001373
1374 onenand_update_bufferram(mtd, from, 0);
1375
1376 ret = this->wait(mtd, FL_READING);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001377 if (unlikely(ret))
1378 ret = onenand_recover_lsb(mtd, from, ret);
1379
Brian Norrisd57f40542011-09-20 18:34:25 -07001380 if (ret && !mtd_is_eccerr(ret)) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05301381 printk(KERN_ERR "%s: read failed = 0x%x\n",
1382 __func__, ret);
Adrian Hunter5f4d47d2007-11-06 09:17:25 +02001383 break;
1384 }
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001385
Brian Norris0612b9d2011-08-30 18:45:40 -07001386 if (mode == MTD_OPS_AUTO_OOB)
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02001387 onenand_transfer_auto_oob(mtd, buf, column, thislen);
1388 else
1389 this->read_bufferram(mtd, ONENAND_SPARERAM, buf, column, thislen);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001390
1391 read += thislen;
1392
1393 if (read == len)
1394 break;
1395
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001396 buf += thislen;
1397
1398 /* Read more? */
1399 if (read < len) {
1400 /* Page size */
Joern Engel28318772006-05-22 23:18:05 +02001401 from += mtd->writesize;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001402 column = 0;
1403 }
1404 }
1405
Kyungmin Park12f77c92007-08-30 09:36:05 +09001406 ops->oobretlen = read;
Adrian Hunter5f4d47d2007-11-06 09:17:25 +02001407
1408 if (ret)
1409 return ret;
1410
1411 if (mtd->ecc_stats.failed - stats.failed)
1412 return -EBADMSG;
1413
1414 return 0;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001415}
1416
Thomas Gleixner8593fbc2006-05-29 03:26:58 +02001417/**
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001418 * onenand_read - [MTD Interface] Read data from flash
1419 * @param mtd MTD device structure
1420 * @param from offset to read from
1421 * @param len number of bytes to read
1422 * @param retlen pointer to variable to store the number of read bytes
1423 * @param buf the databuffer to put data
1424 *
1425 * Read with ecc
1426*/
1427static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
1428 size_t *retlen, u_char *buf)
1429{
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001430 struct onenand_chip *this = mtd->priv;
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001431 struct mtd_oob_ops ops = {
1432 .len = len,
1433 .ooblen = 0,
1434 .datbuf = buf,
1435 .oobbuf = NULL,
1436 };
1437 int ret;
1438
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03001439 onenand_get_device(mtd, FL_READING);
Kyungmin Park8a8f6322010-12-02 09:24:16 +09001440 ret = ONENAND_IS_4KB_PAGE(this) ?
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001441 onenand_mlc_read_ops_nolock(mtd, from, &ops) :
1442 onenand_read_ops_nolock(mtd, from, &ops);
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03001443 onenand_release_device(mtd);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001444
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03001445 *retlen = ops.retlen;
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001446 return ret;
1447}
1448
1449/**
1450 * onenand_read_oob - [MTD Interface] Read main and/or out-of-band
Kyungmin Parke3da8062007-02-15 09:36:39 +09001451 * @param mtd: MTD device structure
1452 * @param from: offset to read from
1453 * @param ops: oob operation description structure
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001454
1455 * Read main and/or out-of-band
Thomas Gleixner8593fbc2006-05-29 03:26:58 +02001456 */
1457static int onenand_read_oob(struct mtd_info *mtd, loff_t from,
1458 struct mtd_oob_ops *ops)
1459{
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001460 struct onenand_chip *this = mtd->priv;
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03001461 int ret;
1462
Kyungmin Park4f4fad22007-02-02 09:22:21 +09001463 switch (ops->mode) {
Brian Norris0612b9d2011-08-30 18:45:40 -07001464 case MTD_OPS_PLACE_OOB:
1465 case MTD_OPS_AUTO_OOB:
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02001466 break;
Brian Norris0612b9d2011-08-30 18:45:40 -07001467 case MTD_OPS_RAW:
Kyungmin Park4f4fad22007-02-02 09:22:21 +09001468 /* Not implemented yet */
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02001469 default:
1470 return -EINVAL;
1471 }
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001472
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03001473 onenand_get_device(mtd, FL_READING);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001474 if (ops->datbuf)
Kyungmin Park8a8f6322010-12-02 09:24:16 +09001475 ret = ONENAND_IS_4KB_PAGE(this) ?
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001476 onenand_mlc_read_ops_nolock(mtd, from, ops) :
1477 onenand_read_ops_nolock(mtd, from, ops);
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03001478 else
1479 ret = onenand_read_oob_nolock(mtd, from, ops);
1480 onenand_release_device(mtd);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001481
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03001482 return ret;
Thomas Gleixner8593fbc2006-05-29 03:26:58 +02001483}
1484
Kyungmin Park211ac752007-02-07 12:15:01 +09001485/**
1486 * onenand_bbt_wait - [DEFAULT] wait until the command is done
1487 * @param mtd MTD device structure
1488 * @param state state to select the max. timeout value
1489 *
1490 * Wait for command done.
1491 */
1492static int onenand_bbt_wait(struct mtd_info *mtd, int state)
1493{
1494 struct onenand_chip *this = mtd->priv;
1495 unsigned long timeout;
Adrian Huntere0c1a922010-12-10 12:04:20 +02001496 unsigned int interrupt, ctrl, ecc, addr1, addr8;
Kyungmin Park211ac752007-02-07 12:15:01 +09001497
1498 /* The 20 msec is enough */
1499 timeout = jiffies + msecs_to_jiffies(20);
1500 while (time_before(jiffies, timeout)) {
1501 interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT);
1502 if (interrupt & ONENAND_INT_MASTER)
1503 break;
1504 }
1505 /* To get correct interrupt status in timeout case */
1506 interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT);
1507 ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS);
Adrian Huntere0c1a922010-12-10 12:04:20 +02001508 addr1 = this->read_word(this->base + ONENAND_REG_START_ADDRESS1);
1509 addr8 = this->read_word(this->base + ONENAND_REG_START_ADDRESS8);
Kyungmin Park211ac752007-02-07 12:15:01 +09001510
Kyungmin Park211ac752007-02-07 12:15:01 +09001511 if (interrupt & ONENAND_INT_READ) {
Adrian Huntere0c1a922010-12-10 12:04:20 +02001512 ecc = onenand_read_ecc(this);
Kyungmin Park83973b82008-05-29 14:52:40 +09001513 if (ecc & ONENAND_ECC_2BIT_ALL) {
Adrian Huntere0c1a922010-12-10 12:04:20 +02001514 printk(KERN_DEBUG "%s: ecc 0x%04x ctrl 0x%04x "
1515 "intr 0x%04x addr1 %#x addr8 %#x\n",
1516 __func__, ecc, ctrl, interrupt, addr1, addr8);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001517 return ONENAND_BBT_READ_ECC_ERROR;
Kyungmin Park83973b82008-05-29 14:52:40 +09001518 }
Kyungmin Park211ac752007-02-07 12:15:01 +09001519 } else {
Adrian Huntere0c1a922010-12-10 12:04:20 +02001520 printk(KERN_ERR "%s: read timeout! ctrl 0x%04x "
1521 "intr 0x%04x addr1 %#x addr8 %#x\n",
1522 __func__, ctrl, interrupt, addr1, addr8);
Kyungmin Park211ac752007-02-07 12:15:01 +09001523 return ONENAND_BBT_READ_FATAL_ERROR;
1524 }
1525
Kyungmin Park83973b82008-05-29 14:52:40 +09001526 /* Initial bad block case: 0x2400 or 0x0400 */
1527 if (ctrl & ONENAND_CTRL_ERROR) {
Adrian Huntere0c1a922010-12-10 12:04:20 +02001528 printk(KERN_DEBUG "%s: ctrl 0x%04x intr 0x%04x addr1 %#x "
1529 "addr8 %#x\n", __func__, ctrl, interrupt, addr1, addr8);
Kyungmin Park83973b82008-05-29 14:52:40 +09001530 return ONENAND_BBT_READ_ERROR;
1531 }
1532
Kyungmin Park211ac752007-02-07 12:15:01 +09001533 return 0;
1534}
1535
1536/**
1537 * onenand_bbt_read_oob - [MTD Interface] OneNAND read out-of-band for bbt scan
1538 * @param mtd MTD device structure
1539 * @param from offset to read from
Kyungmin Parke3da8062007-02-15 09:36:39 +09001540 * @param ops oob operation description structure
Kyungmin Park211ac752007-02-07 12:15:01 +09001541 *
1542 * OneNAND read out-of-band data from the spare area for bbt scan
1543 */
1544int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from,
1545 struct mtd_oob_ops *ops)
1546{
1547 struct onenand_chip *this = mtd->priv;
1548 int read = 0, thislen, column;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001549 int ret = 0, readcmd;
Kyungmin Park211ac752007-02-07 12:15:01 +09001550 size_t len = ops->ooblen;
1551 u_char *buf = ops->oobbuf;
1552
Brian Norris0a32a102011-07-19 10:06:10 -07001553 pr_debug("%s: from = 0x%08x, len = %zi\n", __func__, (unsigned int)from,
1554 len);
Kyungmin Park211ac752007-02-07 12:15:01 +09001555
1556 /* Initialize return value */
1557 ops->oobretlen = 0;
1558
1559 /* Do not allow reads past end of device */
1560 if (unlikely((from + len) > mtd->size)) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05301561 printk(KERN_ERR "%s: Attempt read beyond end of device\n",
1562 __func__);
Kyungmin Park211ac752007-02-07 12:15:01 +09001563 return ONENAND_BBT_READ_FATAL_ERROR;
1564 }
1565
1566 /* Grab the lock and see if the device is available */
1567 onenand_get_device(mtd, FL_READING);
1568
1569 column = from & (mtd->oobsize - 1);
1570
Kyungmin Park8a8f6322010-12-02 09:24:16 +09001571 readcmd = ONENAND_IS_4KB_PAGE(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001572
Kyungmin Park211ac752007-02-07 12:15:01 +09001573 while (read < len) {
1574 cond_resched();
1575
1576 thislen = mtd->oobsize - column;
1577 thislen = min_t(int, thislen, len);
1578
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001579 this->command(mtd, readcmd, from, mtd->oobsize);
Kyungmin Park211ac752007-02-07 12:15:01 +09001580
1581 onenand_update_bufferram(mtd, from, 0);
1582
Kyungmin Park31bb9992009-05-12 13:46:57 -07001583 ret = this->bbt_wait(mtd, FL_READING);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001584 if (unlikely(ret))
1585 ret = onenand_recover_lsb(mtd, from, ret);
1586
Kyungmin Park211ac752007-02-07 12:15:01 +09001587 if (ret)
1588 break;
1589
1590 this->read_bufferram(mtd, ONENAND_SPARERAM, buf, column, thislen);
1591 read += thislen;
1592 if (read == len)
1593 break;
1594
1595 buf += thislen;
1596
1597 /* Read more? */
1598 if (read < len) {
1599 /* Update Page size */
Kyungmin Parkee9745f2007-06-30 13:57:49 +09001600 from += this->writesize;
Kyungmin Park211ac752007-02-07 12:15:01 +09001601 column = 0;
1602 }
1603 }
1604
1605 /* Deselect and wake up anyone waiting on the device */
1606 onenand_release_device(mtd);
1607
1608 ops->oobretlen = read;
1609 return ret;
1610}
1611
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001612#ifdef CONFIG_MTD_ONENAND_VERIFY_WRITE
1613/**
Kyungmin Park8e6ec692006-05-12 17:02:41 +03001614 * onenand_verify_oob - [GENERIC] verify the oob contents after a write
1615 * @param mtd MTD device structure
1616 * @param buf the databuffer to verify
1617 * @param to offset to read from
Kyungmin Park8e6ec692006-05-12 17:02:41 +03001618 */
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02001619static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to)
Kyungmin Park8e6ec692006-05-12 17:02:41 +03001620{
1621 struct onenand_chip *this = mtd->priv;
Kyungmin Park69d79182007-12-14 14:47:21 +09001622 u_char *oob_buf = this->oob_buf;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001623 int status, i, readcmd;
Kyungmin Park8e6ec692006-05-12 17:02:41 +03001624
Kyungmin Park8a8f6322010-12-02 09:24:16 +09001625 readcmd = ONENAND_IS_4KB_PAGE(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001626
1627 this->command(mtd, readcmd, to, mtd->oobsize);
Kyungmin Park8e6ec692006-05-12 17:02:41 +03001628 onenand_update_bufferram(mtd, to, 0);
1629 status = this->wait(mtd, FL_READING);
1630 if (status)
1631 return status;
1632
Kyungmin Park69d79182007-12-14 14:47:21 +09001633 this->read_bufferram(mtd, ONENAND_SPARERAM, oob_buf, 0, mtd->oobsize);
Kyungmin Park91014e92007-02-12 10:34:39 +09001634 for (i = 0; i < mtd->oobsize; i++)
Kyungmin Park69d79182007-12-14 14:47:21 +09001635 if (buf[i] != 0xFF && buf[i] != oob_buf[i])
Kyungmin Park8e6ec692006-05-12 17:02:41 +03001636 return -EBADMSG;
1637
1638 return 0;
1639}
1640
1641/**
Adrian Hunter8b29c0b2007-01-25 14:06:33 +09001642 * onenand_verify - [GENERIC] verify the chip contents after a write
1643 * @param mtd MTD device structure
1644 * @param buf the databuffer to verify
1645 * @param addr offset to read from
1646 * @param len number of bytes to read and compare
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001647 */
Adrian Hunter8b29c0b2007-01-25 14:06:33 +09001648static int onenand_verify(struct mtd_info *mtd, const u_char *buf, loff_t addr, size_t len)
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001649{
1650 struct onenand_chip *this = mtd->priv;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001651 int ret = 0;
Adrian Hunter8b29c0b2007-01-25 14:06:33 +09001652 int thislen, column;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001653
Roman Tereshonkove6da8562011-02-08 12:02:42 +02001654 column = addr & (this->writesize - 1);
1655
Adrian Hunter8b29c0b2007-01-25 14:06:33 +09001656 while (len != 0) {
Roman Tereshonkove6da8562011-02-08 12:02:42 +02001657 thislen = min_t(int, this->writesize - column, len);
Kyungmin Park60d84f92006-12-22 16:21:54 +09001658
Kyungmin Parkee9745f2007-06-30 13:57:49 +09001659 this->command(mtd, ONENAND_CMD_READ, addr, this->writesize);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001660
Adrian Hunter8b29c0b2007-01-25 14:06:33 +09001661 onenand_update_bufferram(mtd, addr, 0);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001662
Adrian Hunter8b29c0b2007-01-25 14:06:33 +09001663 ret = this->wait(mtd, FL_READING);
1664 if (ret)
1665 return ret;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001666
Adrian Hunter8b29c0b2007-01-25 14:06:33 +09001667 onenand_update_bufferram(mtd, addr, 1);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001668
Kyungmin Park3328dc32010-04-28 17:46:47 +02001669 this->read_bufferram(mtd, ONENAND_DATARAM, this->verify_buf, 0, mtd->writesize);
Adrian Hunter8b29c0b2007-01-25 14:06:33 +09001670
Roman Tereshonkove6da8562011-02-08 12:02:42 +02001671 if (memcmp(buf, this->verify_buf + column, thislen))
Adrian Hunter8b29c0b2007-01-25 14:06:33 +09001672 return -EBADMSG;
1673
1674 len -= thislen;
1675 buf += thislen;
1676 addr += thislen;
Roman Tereshonkove6da8562011-02-08 12:02:42 +02001677 column = 0;
Adrian Hunter8b29c0b2007-01-25 14:06:33 +09001678 }
Thomas Gleixnerd5c5e782005-11-07 11:15:51 +00001679
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001680 return 0;
1681}
1682#else
Adrian Hunter8b29c0b2007-01-25 14:06:33 +09001683#define onenand_verify(...) (0)
Kyungmin Park8e6ec692006-05-12 17:02:41 +03001684#define onenand_verify_oob(...) (0)
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001685#endif
1686
Kyungmin Park60d84f92006-12-22 16:21:54 +09001687#define NOTALIGNED(x) ((x & (this->subpagesize - 1)) != 0)
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001688
Richard Purdie6c77fd62008-02-06 10:18:22 +00001689static void onenand_panic_wait(struct mtd_info *mtd)
1690{
1691 struct onenand_chip *this = mtd->priv;
1692 unsigned int interrupt;
1693 int i;
1694
1695 for (i = 0; i < 2000; i++) {
1696 interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT);
1697 if (interrupt & ONENAND_INT_MASTER)
1698 break;
1699 udelay(10);
1700 }
1701}
1702
1703/**
1704 * onenand_panic_write - [MTD Interface] write buffer to FLASH in a panic context
1705 * @param mtd MTD device structure
1706 * @param to offset to write to
1707 * @param len number of bytes to write
1708 * @param retlen pointer to variable to store the number of written bytes
1709 * @param buf the data to write
1710 *
1711 * Write with ECC
1712 */
1713static int onenand_panic_write(struct mtd_info *mtd, loff_t to, size_t len,
1714 size_t *retlen, const u_char *buf)
1715{
1716 struct onenand_chip *this = mtd->priv;
1717 int column, subpage;
1718 int written = 0;
Richard Purdie6c77fd62008-02-06 10:18:22 +00001719
1720 if (this->state == FL_PM_SUSPENDED)
1721 return -EBUSY;
1722
1723 /* Wait for any existing operation to clear */
1724 onenand_panic_wait(mtd);
1725
Brian Norris0a32a102011-07-19 10:06:10 -07001726 pr_debug("%s: to = 0x%08x, len = %i\n", __func__, (unsigned int)to,
1727 (int)len);
Richard Purdie6c77fd62008-02-06 10:18:22 +00001728
Richard Purdie6c77fd62008-02-06 10:18:22 +00001729 /* Reject writes, which are not page aligned */
Roel Kluinb73d7e432008-02-16 18:14:35 +01001730 if (unlikely(NOTALIGNED(to) || NOTALIGNED(len))) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05301731 printk(KERN_ERR "%s: Attempt to write not page aligned data\n",
1732 __func__);
Richard Purdie6c77fd62008-02-06 10:18:22 +00001733 return -EINVAL;
1734 }
1735
1736 column = to & (mtd->writesize - 1);
1737
1738 /* Loop until all data write */
1739 while (written < len) {
1740 int thislen = min_t(int, mtd->writesize - column, len - written);
1741 u_char *wbuf = (u_char *) buf;
1742
1743 this->command(mtd, ONENAND_CMD_BUFFERRAM, to, thislen);
1744
1745 /* Partial page write */
1746 subpage = thislen < mtd->writesize;
1747 if (subpage) {
1748 memset(this->page_buf, 0xff, mtd->writesize);
1749 memcpy(this->page_buf + column, buf, thislen);
1750 wbuf = this->page_buf;
1751 }
1752
1753 this->write_bufferram(mtd, ONENAND_DATARAM, wbuf, 0, mtd->writesize);
1754 this->write_bufferram(mtd, ONENAND_SPARERAM, ffchars, 0, mtd->oobsize);
1755
1756 this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize);
1757
1758 onenand_panic_wait(mtd);
1759
1760 /* In partial page write we don't update bufferram */
Brian Norris7f2a7ce2015-02-28 02:02:25 -08001761 onenand_update_bufferram(mtd, to, !subpage);
Richard Purdie6c77fd62008-02-06 10:18:22 +00001762 if (ONENAND_IS_2PLANE(this)) {
1763 ONENAND_SET_BUFFERRAM1(this);
Brian Norris7f2a7ce2015-02-28 02:02:25 -08001764 onenand_update_bufferram(mtd, to + this->writesize, !subpage);
Richard Purdie6c77fd62008-02-06 10:18:22 +00001765 }
1766
1767 written += thislen;
1768
1769 if (written == len)
1770 break;
1771
1772 column = 0;
1773 to += thislen;
1774 buf += thislen;
1775 }
1776
1777 *retlen = written;
Brian Norris7f2a7ce2015-02-28 02:02:25 -08001778 return 0;
Richard Purdie6c77fd62008-02-06 10:18:22 +00001779}
1780
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001781/**
Brian Norris7854d3f2011-06-23 14:12:08 -07001782 * onenand_fill_auto_oob - [INTERN] oob auto-placement transfer
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02001783 * @param mtd MTD device structure
1784 * @param oob_buf oob buffer
1785 * @param buf source address
1786 * @param column oob offset to write to
1787 * @param thislen oob length to write
1788 */
1789static int onenand_fill_auto_oob(struct mtd_info *mtd, u_char *oob_buf,
1790 const u_char *buf, int column, int thislen)
1791{
Boris Brezillond30aae62016-02-03 20:12:31 +01001792 return mtd_ooblayout_set_databytes(mtd, buf, oob_buf, column, thislen);
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02001793}
1794
1795/**
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03001796 * onenand_write_ops_nolock - [OneNAND Interface] write main and/or out-of-band
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001797 * @param mtd MTD device structure
1798 * @param to offset to write to
1799 * @param ops oob operation description structure
1800 *
1801 * Write main and/or oob with ECC
1802 */
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03001803static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001804 struct mtd_oob_ops *ops)
1805{
1806 struct onenand_chip *this = mtd->priv;
Kyungmin Park9ce96902008-11-17 17:54:28 +09001807 int written = 0, column, thislen = 0, subpage = 0;
1808 int prev = 0, prevlen = 0, prev_subpage = 0, first = 1;
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001809 int oobwritten = 0, oobcolumn, thisooblen, oobsize;
1810 size_t len = ops->len;
1811 size_t ooblen = ops->ooblen;
1812 const u_char *buf = ops->datbuf;
1813 const u_char *oob = ops->oobbuf;
1814 u_char *oobbuf;
Roman Tereshonkovac80dac2010-11-03 12:55:21 +02001815 int ret = 0, cmd;
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001816
Brian Norris0a32a102011-07-19 10:06:10 -07001817 pr_debug("%s: to = 0x%08x, len = %i\n", __func__, (unsigned int)to,
1818 (int)len);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001819
1820 /* Initialize retlen, in case of early exit */
1821 ops->retlen = 0;
1822 ops->oobretlen = 0;
1823
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001824 /* Reject writes, which are not page aligned */
Roel Kluinb73d7e432008-02-16 18:14:35 +01001825 if (unlikely(NOTALIGNED(to) || NOTALIGNED(len))) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05301826 printk(KERN_ERR "%s: Attempt to write not page aligned data\n",
1827 __func__);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001828 return -EINVAL;
1829 }
1830
Kyungmin Park9ce96902008-11-17 17:54:28 +09001831 /* Check zero length */
1832 if (!len)
1833 return 0;
Boris BREZILLON29f10582016-03-07 10:46:52 +01001834 oobsize = mtd_oobavail(mtd, ops);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001835 oobcolumn = to & (mtd->oobsize - 1);
1836
1837 column = to & (mtd->writesize - 1);
1838
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001839 /* Loop until all data write */
Kyungmin Park9ce96902008-11-17 17:54:28 +09001840 while (1) {
1841 if (written < len) {
1842 u_char *wbuf = (u_char *) buf;
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001843
Kyungmin Park9ce96902008-11-17 17:54:28 +09001844 thislen = min_t(int, mtd->writesize - column, len - written);
1845 thisooblen = min_t(int, oobsize - oobcolumn, ooblen - oobwritten);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001846
Kyungmin Park9ce96902008-11-17 17:54:28 +09001847 cond_resched();
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001848
Kyungmin Park9ce96902008-11-17 17:54:28 +09001849 this->command(mtd, ONENAND_CMD_BUFFERRAM, to, thislen);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001850
Kyungmin Park9ce96902008-11-17 17:54:28 +09001851 /* Partial page write */
1852 subpage = thislen < mtd->writesize;
1853 if (subpage) {
1854 memset(this->page_buf, 0xff, mtd->writesize);
1855 memcpy(this->page_buf + column, buf, thislen);
1856 wbuf = this->page_buf;
1857 }
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001858
Kyungmin Park9ce96902008-11-17 17:54:28 +09001859 this->write_bufferram(mtd, ONENAND_DATARAM, wbuf, 0, mtd->writesize);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001860
Kyungmin Park9ce96902008-11-17 17:54:28 +09001861 if (oob) {
1862 oobbuf = this->oob_buf;
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001863
Kyungmin Park9ce96902008-11-17 17:54:28 +09001864 /* We send data to spare ram with oobsize
1865 * to prevent byte access */
1866 memset(oobbuf, 0xff, mtd->oobsize);
Brian Norris0612b9d2011-08-30 18:45:40 -07001867 if (ops->mode == MTD_OPS_AUTO_OOB)
Kyungmin Park9ce96902008-11-17 17:54:28 +09001868 onenand_fill_auto_oob(mtd, oobbuf, oob, oobcolumn, thisooblen);
1869 else
1870 memcpy(oobbuf + oobcolumn, oob, thisooblen);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001871
Kyungmin Park9ce96902008-11-17 17:54:28 +09001872 oobwritten += thisooblen;
1873 oob += thisooblen;
1874 oobcolumn = 0;
1875 } else
1876 oobbuf = (u_char *) ffchars;
1877
1878 this->write_bufferram(mtd, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001879 } else
Kyungmin Park9ce96902008-11-17 17:54:28 +09001880 ONENAND_SET_NEXT_BUFFERRAM(this);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001881
Kyungmin Park9ce96902008-11-17 17:54:28 +09001882 /*
Mika Korhonen492e1502009-06-09 21:52:35 +03001883 * 2 PLANE, MLC, and Flex-OneNAND do not support
1884 * write-while-program feature.
Kyungmin Park9ce96902008-11-17 17:54:28 +09001885 */
Kyungmin Park6a88c472010-04-28 17:46:45 +02001886 if (!ONENAND_IS_2PLANE(this) && !ONENAND_IS_4KB_PAGE(this) && !first) {
Kyungmin Park9ce96902008-11-17 17:54:28 +09001887 ONENAND_SET_PREV_BUFFERRAM(this);
1888
1889 ret = this->wait(mtd, FL_WRITING);
1890
1891 /* In partial page write we don't update bufferram */
1892 onenand_update_bufferram(mtd, prev, !ret && !prev_subpage);
1893 if (ret) {
1894 written -= prevlen;
Amul Kumar Saha297758f2009-10-02 16:59:11 +05301895 printk(KERN_ERR "%s: write failed %d\n",
1896 __func__, ret);
Kyungmin Park9ce96902008-11-17 17:54:28 +09001897 break;
1898 }
1899
1900 if (written == len) {
1901 /* Only check verify write turn on */
1902 ret = onenand_verify(mtd, buf - len, to - len, len);
1903 if (ret)
Amul Kumar Saha297758f2009-10-02 16:59:11 +05301904 printk(KERN_ERR "%s: verify failed %d\n",
1905 __func__, ret);
Kyungmin Park9ce96902008-11-17 17:54:28 +09001906 break;
1907 }
1908
1909 ONENAND_SET_NEXT_BUFFERRAM(this);
1910 }
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001911
Roman Tereshonkovac80dac2010-11-03 12:55:21 +02001912 this->ongoing = 0;
1913 cmd = ONENAND_CMD_PROG;
1914
1915 /* Exclude 1st OTP and OTP blocks for cache program feature */
1916 if (ONENAND_IS_CACHE_PROGRAM(this) &&
1917 likely(onenand_block(this, to) != 0) &&
1918 ONENAND_IS_4KB_PAGE(this) &&
1919 ((written + thislen) < len)) {
1920 cmd = ONENAND_CMD_2X_CACHE_PROG;
1921 this->ongoing = 1;
1922 }
1923
1924 this->command(mtd, cmd, to, mtd->writesize);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001925
Kyungmin Park9ce96902008-11-17 17:54:28 +09001926 /*
1927 * 2 PLANE, MLC, and Flex-OneNAND wait here
1928 */
Kyungmin Park6a88c472010-04-28 17:46:45 +02001929 if (ONENAND_IS_2PLANE(this) || ONENAND_IS_4KB_PAGE(this)) {
Kyungmin Park9ce96902008-11-17 17:54:28 +09001930 ret = this->wait(mtd, FL_WRITING);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001931
Kyungmin Park9ce96902008-11-17 17:54:28 +09001932 /* In partial page write we don't update bufferram */
1933 onenand_update_bufferram(mtd, to, !ret && !subpage);
1934 if (ret) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05301935 printk(KERN_ERR "%s: write failed %d\n",
1936 __func__, ret);
Kyungmin Park9ce96902008-11-17 17:54:28 +09001937 break;
1938 }
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001939
Kyungmin Park9ce96902008-11-17 17:54:28 +09001940 /* Only check verify write turn on */
1941 ret = onenand_verify(mtd, buf, to, thislen);
1942 if (ret) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05301943 printk(KERN_ERR "%s: verify failed %d\n",
1944 __func__, ret);
Kyungmin Park9ce96902008-11-17 17:54:28 +09001945 break;
1946 }
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001947
Kyungmin Park9ce96902008-11-17 17:54:28 +09001948 written += thislen;
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001949
Kyungmin Park9ce96902008-11-17 17:54:28 +09001950 if (written == len)
1951 break;
1952
1953 } else
1954 written += thislen;
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001955
1956 column = 0;
Kyungmin Park9ce96902008-11-17 17:54:28 +09001957 prev_subpage = subpage;
1958 prev = to;
1959 prevlen = thislen;
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001960 to += thislen;
1961 buf += thislen;
Kyungmin Park9ce96902008-11-17 17:54:28 +09001962 first = 0;
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001963 }
1964
Kyungmin Park9ce96902008-11-17 17:54:28 +09001965 /* In error case, clear all bufferrams */
1966 if (written != len)
1967 onenand_invalidate_bufferram(mtd, 0, -1);
1968
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001969 ops->retlen = written;
Kyungmin Park9ce96902008-11-17 17:54:28 +09001970 ops->oobretlen = oobwritten;
Kyungmin Parkd15057b2007-09-06 10:06:12 +09001971
1972 return ret;
1973}
1974
1975
1976/**
Brian Norris7854d3f2011-06-23 14:12:08 -07001977 * onenand_write_oob_nolock - [INTERN] OneNAND write out-of-band
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001978 * @param mtd MTD device structure
1979 * @param to offset to write to
1980 * @param len number of bytes to write
1981 * @param retlen pointer to variable to store the number of written bytes
1982 * @param buf the data to write
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02001983 * @param mode operation mode
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001984 *
1985 * OneNAND write out-of-band
1986 */
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03001987static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to,
1988 struct mtd_oob_ops *ops)
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001989{
1990 struct onenand_chip *this = mtd->priv;
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02001991 int column, ret = 0, oobsize;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07001992 int written = 0, oobcmd;
Kyungmin Park91014e92007-02-12 10:34:39 +09001993 u_char *oobbuf;
Kyungmin Park12f77c92007-08-30 09:36:05 +09001994 size_t len = ops->ooblen;
1995 const u_char *buf = ops->oobbuf;
Brian Norris905c6bc2011-08-30 18:45:39 -07001996 unsigned int mode = ops->mode;
Kyungmin Park12f77c92007-08-30 09:36:05 +09001997
1998 to += ops->ooboffs;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01001999
Brian Norris0a32a102011-07-19 10:06:10 -07002000 pr_debug("%s: to = 0x%08x, len = %i\n", __func__, (unsigned int)to,
2001 (int)len);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002002
2003 /* Initialize retlen, in case of early exit */
Kyungmin Park12f77c92007-08-30 09:36:05 +09002004 ops->oobretlen = 0;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002005
Brian Norris0612b9d2011-08-30 18:45:40 -07002006 if (mode == MTD_OPS_AUTO_OOB)
Boris BREZILLONf5b8aa72016-03-07 10:46:51 +01002007 oobsize = mtd->oobavail;
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02002008 else
2009 oobsize = mtd->oobsize;
2010
2011 column = to & (mtd->oobsize - 1);
2012
2013 if (unlikely(column >= oobsize)) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05302014 printk(KERN_ERR "%s: Attempted to start write outside oob\n",
2015 __func__);
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02002016 return -EINVAL;
2017 }
2018
Adrian Hunter52e42002007-02-06 09:15:39 +09002019 /* For compatibility with NAND: Do not allow write past end of page */
Kyungmin Park91014e92007-02-12 10:34:39 +09002020 if (unlikely(column + len > oobsize)) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05302021 printk(KERN_ERR "%s: Attempt to write past end of page\n",
2022 __func__);
Adrian Hunter52e42002007-02-06 09:15:39 +09002023 return -EINVAL;
2024 }
2025
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02002026 /* Do not allow reads past end of device */
2027 if (unlikely(to >= mtd->size ||
2028 column + len > ((mtd->size >> this->page_shift) -
2029 (to >> this->page_shift)) * oobsize)) {
David Woodhouse80327472009-10-05 08:30:04 +01002030 printk(KERN_ERR "%s: Attempted to write past end of device\n",
2031 __func__);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002032 return -EINVAL;
2033 }
2034
Kyungmin Park470bc842007-03-09 10:08:11 +09002035 oobbuf = this->oob_buf;
Kyungmin Park91014e92007-02-12 10:34:39 +09002036
Kyungmin Park8a8f6322010-12-02 09:24:16 +09002037 oobcmd = ONENAND_IS_4KB_PAGE(this) ? ONENAND_CMD_PROG : ONENAND_CMD_PROGOOB;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002038
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002039 /* Loop until all data write */
2040 while (written < len) {
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02002041 int thislen = min_t(int, oobsize, len - written);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002042
Artem Bityutskiy61a7e192006-12-26 16:41:24 +09002043 cond_resched();
2044
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002045 this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->oobsize);
2046
Kyungmin Park34c10602006-05-12 17:02:46 +03002047 /* We send data to spare ram with oobsize
2048 * to prevent byte access */
Kyungmin Park91014e92007-02-12 10:34:39 +09002049 memset(oobbuf, 0xff, mtd->oobsize);
Brian Norris0612b9d2011-08-30 18:45:40 -07002050 if (mode == MTD_OPS_AUTO_OOB)
Kyungmin Park91014e92007-02-12 10:34:39 +09002051 onenand_fill_auto_oob(mtd, oobbuf, buf, column, thislen);
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02002052 else
Kyungmin Park91014e92007-02-12 10:34:39 +09002053 memcpy(oobbuf + column, buf, thislen);
2054 this->write_bufferram(mtd, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002055
Kyungmin Park8a8f6322010-12-02 09:24:16 +09002056 if (ONENAND_IS_4KB_PAGE(this)) {
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002057 /* Set main area of DataRAM to 0xff*/
2058 memset(this->page_buf, 0xff, mtd->writesize);
2059 this->write_bufferram(mtd, ONENAND_DATARAM,
2060 this->page_buf, 0, mtd->writesize);
2061 }
2062
2063 this->command(mtd, oobcmd, to, mtd->oobsize);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002064
2065 onenand_update_bufferram(mtd, to, 0);
Kyungmin Parkee9745f2007-06-30 13:57:49 +09002066 if (ONENAND_IS_2PLANE(this)) {
2067 ONENAND_SET_BUFFERRAM1(this);
2068 onenand_update_bufferram(mtd, to + this->writesize, 0);
2069 }
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002070
Kyungmin Park8e6ec692006-05-12 17:02:41 +03002071 ret = this->wait(mtd, FL_WRITING);
2072 if (ret) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05302073 printk(KERN_ERR "%s: write failed %d\n", __func__, ret);
Kyungmin Park5b4246f2007-02-02 09:39:21 +09002074 break;
Kyungmin Park8e6ec692006-05-12 17:02:41 +03002075 }
2076
Kyungmin Park91014e92007-02-12 10:34:39 +09002077 ret = onenand_verify_oob(mtd, oobbuf, to);
Kyungmin Park8e6ec692006-05-12 17:02:41 +03002078 if (ret) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05302079 printk(KERN_ERR "%s: verify failed %d\n",
2080 __func__, ret);
Kyungmin Park5b4246f2007-02-02 09:39:21 +09002081 break;
Kyungmin Park8e6ec692006-05-12 17:02:41 +03002082 }
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002083
2084 written += thislen;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002085 if (written == len)
2086 break;
2087
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02002088 to += mtd->writesize;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002089 buf += thislen;
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02002090 column = 0;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002091 }
2092
Kyungmin Park12f77c92007-08-30 09:36:05 +09002093 ops->oobretlen = written;
Thomas Gleixnerd5c5e782005-11-07 11:15:51 +00002094
Kyungmin Park8e6ec692006-05-12 17:02:41 +03002095 return ret;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002096}
2097
2098/**
Kyungmin Parkd15057b2007-09-06 10:06:12 +09002099 * onenand_write - [MTD Interface] write buffer to FLASH
2100 * @param mtd MTD device structure
2101 * @param to offset to write to
2102 * @param len number of bytes to write
2103 * @param retlen pointer to variable to store the number of written bytes
2104 * @param buf the data to write
2105 *
2106 * Write with ECC
2107 */
2108static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len,
2109 size_t *retlen, const u_char *buf)
2110{
2111 struct mtd_oob_ops ops = {
2112 .len = len,
2113 .ooblen = 0,
2114 .datbuf = (u_char *) buf,
2115 .oobbuf = NULL,
2116 };
2117 int ret;
2118
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002119 onenand_get_device(mtd, FL_WRITING);
2120 ret = onenand_write_ops_nolock(mtd, to, &ops);
2121 onenand_release_device(mtd);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09002122
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002123 *retlen = ops.retlen;
Kyungmin Parkd15057b2007-09-06 10:06:12 +09002124 return ret;
2125}
2126
2127/**
Thomas Gleixner8593fbc2006-05-29 03:26:58 +02002128 * onenand_write_oob - [MTD Interface] NAND write data and/or out-of-band
Kyungmin Parke3da8062007-02-15 09:36:39 +09002129 * @param mtd: MTD device structure
2130 * @param to: offset to write
2131 * @param ops: oob operation description structure
Thomas Gleixner8593fbc2006-05-29 03:26:58 +02002132 */
2133static int onenand_write_oob(struct mtd_info *mtd, loff_t to,
2134 struct mtd_oob_ops *ops)
2135{
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002136 int ret;
2137
Kyungmin Park4f4fad22007-02-02 09:22:21 +09002138 switch (ops->mode) {
Brian Norris0612b9d2011-08-30 18:45:40 -07002139 case MTD_OPS_PLACE_OOB:
2140 case MTD_OPS_AUTO_OOB:
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02002141 break;
Brian Norris0612b9d2011-08-30 18:45:40 -07002142 case MTD_OPS_RAW:
Kyungmin Park4f4fad22007-02-02 09:22:21 +09002143 /* Not implemented yet */
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02002144 default:
2145 return -EINVAL;
2146 }
Kyungmin Parkd15057b2007-09-06 10:06:12 +09002147
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002148 onenand_get_device(mtd, FL_WRITING);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09002149 if (ops->datbuf)
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002150 ret = onenand_write_ops_nolock(mtd, to, ops);
2151 else
2152 ret = onenand_write_oob_nolock(mtd, to, ops);
2153 onenand_release_device(mtd);
Kyungmin Parkd15057b2007-09-06 10:06:12 +09002154
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002155 return ret;
Thomas Gleixner8593fbc2006-05-29 03:26:58 +02002156}
2157
2158/**
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002159 * onenand_block_isbad_nolock - [GENERIC] Check if a block is marked bad
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002160 * @param mtd MTD device structure
2161 * @param ofs offset from device start
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002162 * @param allowbbt 1, if its allowed to access the bbt area
2163 *
2164 * Check, if the block is bad. Either by reading the bad block table or
2165 * calling of the scan function.
2166 */
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002167static int onenand_block_isbad_nolock(struct mtd_info *mtd, loff_t ofs, int allowbbt)
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002168{
2169 struct onenand_chip *this = mtd->priv;
2170 struct bbm_info *bbm = this->bbm;
2171
2172 /* Return info from the table */
2173 return bbm->isbad_bbt(mtd, ofs, allowbbt);
2174}
2175
Mika Korhonen72073022009-10-23 07:50:43 +02002176
2177static int onenand_multiblock_erase_verify(struct mtd_info *mtd,
2178 struct erase_info *instr)
2179{
2180 struct onenand_chip *this = mtd->priv;
2181 loff_t addr = instr->addr;
2182 int len = instr->len;
2183 unsigned int block_size = (1 << this->erase_shift);
2184 int ret = 0;
2185
2186 while (len) {
2187 this->command(mtd, ONENAND_CMD_ERASE_VERIFY, addr, block_size);
2188 ret = this->wait(mtd, FL_VERIFYING_ERASE);
2189 if (ret) {
2190 printk(KERN_ERR "%s: Failed verify, block %d\n",
2191 __func__, onenand_block(this, addr));
2192 instr->state = MTD_ERASE_FAILED;
2193 instr->fail_addr = addr;
2194 return -1;
2195 }
2196 len -= block_size;
2197 addr += block_size;
2198 }
2199 return 0;
2200}
2201
2202/**
Brian Norris7854d3f2011-06-23 14:12:08 -07002203 * onenand_multiblock_erase - [INTERN] erase block(s) using multiblock erase
Mika Korhonen72073022009-10-23 07:50:43 +02002204 * @param mtd MTD device structure
2205 * @param instr erase instruction
2206 * @param region erase region
2207 *
2208 * Erase one or more blocks up to 64 block at a time
2209 */
2210static int onenand_multiblock_erase(struct mtd_info *mtd,
2211 struct erase_info *instr,
2212 unsigned int block_size)
2213{
2214 struct onenand_chip *this = mtd->priv;
2215 loff_t addr = instr->addr;
2216 int len = instr->len;
2217 int eb_count = 0;
2218 int ret = 0;
2219 int bdry_block = 0;
2220
2221 instr->state = MTD_ERASING;
2222
2223 if (ONENAND_IS_DDP(this)) {
2224 loff_t bdry_addr = this->chipsize >> 1;
2225 if (addr < bdry_addr && (addr + len) > bdry_addr)
2226 bdry_block = bdry_addr >> this->erase_shift;
2227 }
2228
2229 /* Pre-check bbs */
2230 while (len) {
2231 /* Check if we have a bad block, we do not erase bad blocks */
2232 if (onenand_block_isbad_nolock(mtd, addr, 0)) {
2233 printk(KERN_WARNING "%s: attempt to erase a bad block "
2234 "at addr 0x%012llx\n",
2235 __func__, (unsigned long long) addr);
2236 instr->state = MTD_ERASE_FAILED;
2237 return -EIO;
2238 }
2239 len -= block_size;
2240 addr += block_size;
2241 }
2242
2243 len = instr->len;
2244 addr = instr->addr;
2245
2246 /* loop over 64 eb batches */
2247 while (len) {
2248 struct erase_info verify_instr = *instr;
2249 int max_eb_count = MB_ERASE_MAX_BLK_COUNT;
2250
2251 verify_instr.addr = addr;
2252 verify_instr.len = 0;
2253
2254 /* do not cross chip boundary */
2255 if (bdry_block) {
2256 int this_block = (addr >> this->erase_shift);
2257
2258 if (this_block < bdry_block) {
2259 max_eb_count = min(max_eb_count,
2260 (bdry_block - this_block));
2261 }
2262 }
2263
2264 eb_count = 0;
2265
2266 while (len > block_size && eb_count < (max_eb_count - 1)) {
2267 this->command(mtd, ONENAND_CMD_MULTIBLOCK_ERASE,
2268 addr, block_size);
2269 onenand_invalidate_bufferram(mtd, addr, block_size);
2270
2271 ret = this->wait(mtd, FL_PREPARING_ERASE);
2272 if (ret) {
2273 printk(KERN_ERR "%s: Failed multiblock erase, "
2274 "block %d\n", __func__,
2275 onenand_block(this, addr));
2276 instr->state = MTD_ERASE_FAILED;
2277 instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN;
2278 return -EIO;
2279 }
2280
2281 len -= block_size;
2282 addr += block_size;
2283 eb_count++;
2284 }
2285
2286 /* last block of 64-eb series */
2287 cond_resched();
2288 this->command(mtd, ONENAND_CMD_ERASE, addr, block_size);
2289 onenand_invalidate_bufferram(mtd, addr, block_size);
2290
2291 ret = this->wait(mtd, FL_ERASING);
2292 /* Check if it is write protected */
2293 if (ret) {
2294 printk(KERN_ERR "%s: Failed erase, block %d\n",
2295 __func__, onenand_block(this, addr));
2296 instr->state = MTD_ERASE_FAILED;
2297 instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN;
2298 return -EIO;
2299 }
2300
2301 len -= block_size;
2302 addr += block_size;
2303 eb_count++;
2304
2305 /* verify */
2306 verify_instr.len = eb_count * block_size;
2307 if (onenand_multiblock_erase_verify(mtd, &verify_instr)) {
2308 instr->state = verify_instr.state;
2309 instr->fail_addr = verify_instr.fail_addr;
2310 return -EIO;
2311 }
2312
2313 }
2314 return 0;
2315}
2316
2317
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002318/**
Brian Norris7854d3f2011-06-23 14:12:08 -07002319 * onenand_block_by_block_erase - [INTERN] erase block(s) using regular erase
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002320 * @param mtd MTD device structure
2321 * @param instr erase instruction
Mika Korhonen73885ae2009-10-23 07:50:42 +02002322 * @param region erase region
2323 * @param block_size erase block size
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002324 *
Mika Korhonen73885ae2009-10-23 07:50:42 +02002325 * Erase one or more blocks one block at a time
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002326 */
Mika Korhonen73885ae2009-10-23 07:50:42 +02002327static int onenand_block_by_block_erase(struct mtd_info *mtd,
2328 struct erase_info *instr,
2329 struct mtd_erase_region_info *region,
2330 unsigned int block_size)
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002331{
2332 struct onenand_chip *this = mtd->priv;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002333 loff_t addr = instr->addr;
Mika Korhonen73885ae2009-10-23 07:50:42 +02002334 int len = instr->len;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002335 loff_t region_end = 0;
Mika Korhonen73885ae2009-10-23 07:50:42 +02002336 int ret = 0;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002337
Mika Korhonen73885ae2009-10-23 07:50:42 +02002338 if (region) {
2339 /* region is set for Flex-OneNAND */
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002340 region_end = region->offset + region->erasesize * region->numblocks;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002341 }
2342
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002343 instr->state = MTD_ERASING;
2344
Mika Korhonen73885ae2009-10-23 07:50:42 +02002345 /* Loop through the blocks */
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002346 while (len) {
Artem Bityutskiy61a7e192006-12-26 16:41:24 +09002347 cond_resched();
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002348
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002349 /* Check if we have a bad block, we do not erase bad blocks */
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002350 if (onenand_block_isbad_nolock(mtd, addr, 0)) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05302351 printk(KERN_WARNING "%s: attempt to erase a bad block "
2352 "at addr 0x%012llx\n",
2353 __func__, (unsigned long long) addr);
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002354 instr->state = MTD_ERASE_FAILED;
Mika Korhonen73885ae2009-10-23 07:50:42 +02002355 return -EIO;
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002356 }
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002357
2358 this->command(mtd, ONENAND_CMD_ERASE, addr, block_size);
2359
Adrian Hunter480b9df2007-02-07 13:55:19 +02002360 onenand_invalidate_bufferram(mtd, addr, block_size);
2361
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002362 ret = this->wait(mtd, FL_ERASING);
2363 /* Check, if it is write protected */
2364 if (ret) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05302365 printk(KERN_ERR "%s: Failed erase, block %d\n",
2366 __func__, onenand_block(this, addr));
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002367 instr->state = MTD_ERASE_FAILED;
2368 instr->fail_addr = addr;
Mika Korhonen73885ae2009-10-23 07:50:42 +02002369 return -EIO;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002370 }
2371
2372 len -= block_size;
2373 addr += block_size;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002374
john.maxin@nokia.comeff3bba2011-05-06 09:17:21 +00002375 if (region && addr == region_end) {
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002376 if (!len)
2377 break;
2378 region++;
2379
2380 block_size = region->erasesize;
2381 region_end = region->offset + region->erasesize * region->numblocks;
2382
2383 if (len & (block_size - 1)) {
2384 /* FIXME: This should be handled at MTD partitioning level. */
Amul Kumar Saha297758f2009-10-02 16:59:11 +05302385 printk(KERN_ERR "%s: Unaligned address\n",
2386 __func__);
Mika Korhonen73885ae2009-10-23 07:50:42 +02002387 return -EIO;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002388 }
2389 }
Mika Korhonen73885ae2009-10-23 07:50:42 +02002390 }
2391 return 0;
2392}
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002393
Mika Korhonen73885ae2009-10-23 07:50:42 +02002394/**
2395 * onenand_erase - [MTD Interface] erase block(s)
2396 * @param mtd MTD device structure
2397 * @param instr erase instruction
2398 *
2399 * Erase one or more blocks
2400 */
2401static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
2402{
2403 struct onenand_chip *this = mtd->priv;
2404 unsigned int block_size;
2405 loff_t addr = instr->addr;
2406 loff_t len = instr->len;
2407 int ret = 0;
2408 struct mtd_erase_region_info *region = NULL;
2409 loff_t region_offset = 0;
2410
Brian Norris289c0522011-07-19 10:06:09 -07002411 pr_debug("%s: start=0x%012llx, len=%llu\n", __func__,
Brian Norris0a32a102011-07-19 10:06:10 -07002412 (unsigned long long)instr->addr,
2413 (unsigned long long)instr->len);
Mika Korhonen73885ae2009-10-23 07:50:42 +02002414
Mika Korhonen73885ae2009-10-23 07:50:42 +02002415 if (FLEXONENAND(this)) {
2416 /* Find the eraseregion of this address */
2417 int i = flexonenand_region(mtd, addr);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002418
Mika Korhonen73885ae2009-10-23 07:50:42 +02002419 region = &mtd->eraseregions[i];
2420 block_size = region->erasesize;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002421
Mika Korhonen73885ae2009-10-23 07:50:42 +02002422 /* Start address within region must align on block boundary.
2423 * Erase region's start offset is always block start address.
2424 */
2425 region_offset = region->offset;
2426 } else
2427 block_size = 1 << this->erase_shift;
2428
2429 /* Start address must align on block boundary */
2430 if (unlikely((addr - region_offset) & (block_size - 1))) {
2431 printk(KERN_ERR "%s: Unaligned address\n", __func__);
2432 return -EINVAL;
2433 }
2434
2435 /* Length must align on block boundary */
2436 if (unlikely(len & (block_size - 1))) {
2437 printk(KERN_ERR "%s: Length not block aligned\n", __func__);
2438 return -EINVAL;
2439 }
2440
Mika Korhonen73885ae2009-10-23 07:50:42 +02002441 /* Grab the lock and see if the device is available */
2442 onenand_get_device(mtd, FL_ERASING);
2443
Kyungmin Parkd983c542010-12-06 09:05:18 +09002444 if (ONENAND_IS_4KB_PAGE(this) || region ||
2445 instr->len < MB_ERASE_MIN_BLK_COUNT * block_size) {
Mika Korhonen72073022009-10-23 07:50:43 +02002446 /* region is set for Flex-OneNAND (no mb erase) */
2447 ret = onenand_block_by_block_erase(mtd, instr,
2448 region, block_size);
2449 } else {
2450 ret = onenand_multiblock_erase(mtd, instr, block_size);
2451 }
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002452
2453 /* Deselect and wake up anyone waiting on the device */
2454 onenand_release_device(mtd);
2455
Adrian Hunter3cd3a862007-10-12 10:34:01 +03002456 /* Do call back function */
Mika Korhonen73885ae2009-10-23 07:50:42 +02002457 if (!ret) {
2458 instr->state = MTD_ERASE_DONE;
Adrian Hunter3cd3a862007-10-12 10:34:01 +03002459 mtd_erase_callback(instr);
Mika Korhonen73885ae2009-10-23 07:50:42 +02002460 }
Adrian Hunter3cd3a862007-10-12 10:34:01 +03002461
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002462 return ret;
2463}
2464
2465/**
2466 * onenand_sync - [MTD Interface] sync
2467 * @param mtd MTD device structure
2468 *
2469 * Sync is actually a wait for chip ready function
2470 */
2471static void onenand_sync(struct mtd_info *mtd)
2472{
Brian Norris289c0522011-07-19 10:06:09 -07002473 pr_debug("%s: called\n", __func__);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002474
2475 /* Grab the lock and see if the device is available */
2476 onenand_get_device(mtd, FL_SYNCING);
2477
2478 /* Release it and go back */
2479 onenand_release_device(mtd);
2480}
2481
2482/**
2483 * onenand_block_isbad - [MTD Interface] Check whether the block at the given offset is bad
2484 * @param mtd MTD device structure
2485 * @param ofs offset relative to mtd start
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002486 *
2487 * Check whether the block is bad
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002488 */
2489static int onenand_block_isbad(struct mtd_info *mtd, loff_t ofs)
2490{
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002491 int ret;
2492
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002493 onenand_get_device(mtd, FL_READING);
2494 ret = onenand_block_isbad_nolock(mtd, ofs, 0);
2495 onenand_release_device(mtd);
2496 return ret;
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002497}
2498
2499/**
2500 * onenand_default_block_markbad - [DEFAULT] mark a block bad
2501 * @param mtd MTD device structure
2502 * @param ofs offset from device start
2503 *
2504 * This is the default implementation, which can be overridden by
2505 * a hardware specific driver.
2506 */
2507static int onenand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
2508{
2509 struct onenand_chip *this = mtd->priv;
2510 struct bbm_info *bbm = this->bbm;
2511 u_char buf[2] = {0, 0};
Kyungmin Park12f77c92007-08-30 09:36:05 +09002512 struct mtd_oob_ops ops = {
Brian Norris0612b9d2011-08-30 18:45:40 -07002513 .mode = MTD_OPS_PLACE_OOB,
Kyungmin Park12f77c92007-08-30 09:36:05 +09002514 .ooblen = 2,
2515 .oobbuf = buf,
2516 .ooboffs = 0,
2517 };
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002518 int block;
2519
2520 /* Get block number */
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002521 block = onenand_block(this, ofs);
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002522 if (bbm->bbt)
2523 bbm->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1);
2524
Mika Korhonen492e1502009-06-09 21:52:35 +03002525 /* We write two bytes, so we don't have to mess with 16-bit access */
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002526 ofs += mtd->oobsize + (bbm->badblockpos & ~0x01);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002527 /* FIXME : What to do when marking SLC block in partition
2528 * with MLC erasesize? For now, it is not advisable to
2529 * create partitions containing both SLC and MLC regions.
2530 */
2531 return onenand_write_oob_nolock(mtd, ofs, &ops);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002532}
2533
2534/**
2535 * onenand_block_markbad - [MTD Interface] Mark the block at the given offset as bad
2536 * @param mtd MTD device structure
2537 * @param ofs offset relative to mtd start
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002538 *
2539 * Mark the block as bad
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002540 */
2541static int onenand_block_markbad(struct mtd_info *mtd, loff_t ofs)
2542{
Aaro Koskinen5e64c292016-02-20 22:27:48 +02002543 struct onenand_chip *this = mtd->priv;
Kyungmin Parkcdc00132005-09-03 07:15:48 +01002544 int ret;
2545
2546 ret = onenand_block_isbad(mtd, ofs);
2547 if (ret) {
2548 /* If it was bad already, return success and do nothing */
2549 if (ret > 0)
2550 return 0;
2551 return ret;
2552 }
2553
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002554 onenand_get_device(mtd, FL_WRITING);
Aaro Koskinen5e64c292016-02-20 22:27:48 +02002555 ret = this->block_markbad(mtd, ofs);
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002556 onenand_release_device(mtd);
2557 return ret;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002558}
2559
2560/**
Kyungmin Park08f782b2006-11-16 11:29:39 +09002561 * onenand_do_lock_cmd - [OneNAND Interface] Lock or unlock block(s)
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002562 * @param mtd MTD device structure
2563 * @param ofs offset relative to mtd start
Kyungmin Park08f782b2006-11-16 11:29:39 +09002564 * @param len number of bytes to lock or unlock
Kyungmin Parke3da8062007-02-15 09:36:39 +09002565 * @param cmd lock or unlock command
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002566 *
Kyungmin Park08f782b2006-11-16 11:29:39 +09002567 * Lock or unlock one or more blocks
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002568 */
Kyungmin Park08f782b2006-11-16 11:29:39 +09002569static int onenand_do_lock_cmd(struct mtd_info *mtd, loff_t ofs, size_t len, int cmd)
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002570{
2571 struct onenand_chip *this = mtd->priv;
2572 int start, end, block, value, status;
Kyungmin Park08f782b2006-11-16 11:29:39 +09002573 int wp_status_mask;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002574
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002575 start = onenand_block(this, ofs);
2576 end = onenand_block(this, ofs + len) - 1;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002577
Kyungmin Park08f782b2006-11-16 11:29:39 +09002578 if (cmd == ONENAND_CMD_LOCK)
2579 wp_status_mask = ONENAND_WP_LS;
2580 else
2581 wp_status_mask = ONENAND_WP_US;
2582
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002583 /* Continuous lock scheme */
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002584 if (this->options & ONENAND_HAS_CONT_LOCK) {
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002585 /* Set start block address */
2586 this->write_word(start, this->base + ONENAND_REG_START_BLOCK_ADDRESS);
2587 /* Set end block address */
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002588 this->write_word(end, this->base + ONENAND_REG_END_BLOCK_ADDRESS);
Kyungmin Park08f782b2006-11-16 11:29:39 +09002589 /* Write lock command */
2590 this->command(mtd, cmd, 0, 0);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002591
2592 /* There's no return value */
Kyungmin Park08f782b2006-11-16 11:29:39 +09002593 this->wait(mtd, FL_LOCKING);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002594
2595 /* Sanity check */
2596 while (this->read_word(this->base + ONENAND_REG_CTRL_STATUS)
2597 & ONENAND_CTRL_ONGO)
2598 continue;
2599
2600 /* Check lock status */
2601 status = this->read_word(this->base + ONENAND_REG_WP_STATUS);
Kyungmin Park08f782b2006-11-16 11:29:39 +09002602 if (!(status & wp_status_mask))
Amul Kumar Saha297758f2009-10-02 16:59:11 +05302603 printk(KERN_ERR "%s: wp status = 0x%x\n",
2604 __func__, status);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002605
2606 return 0;
2607 }
2608
2609 /* Block lock scheme */
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002610 for (block = start; block < end + 1; block++) {
Kyungmin Park20ba89a2005-12-16 11:17:29 +09002611 /* Set block address */
2612 value = onenand_block_address(this, block);
2613 this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1);
2614 /* Select DataRAM for DDP */
2615 value = onenand_bufferram_address(this, block);
2616 this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002617 /* Set start block address */
2618 this->write_word(block, this->base + ONENAND_REG_START_BLOCK_ADDRESS);
Kyungmin Park08f782b2006-11-16 11:29:39 +09002619 /* Write lock command */
2620 this->command(mtd, cmd, 0, 0);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002621
2622 /* There's no return value */
Kyungmin Park08f782b2006-11-16 11:29:39 +09002623 this->wait(mtd, FL_LOCKING);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002624
2625 /* Sanity check */
2626 while (this->read_word(this->base + ONENAND_REG_CTRL_STATUS)
2627 & ONENAND_CTRL_ONGO)
2628 continue;
2629
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002630 /* Check lock status */
2631 status = this->read_word(this->base + ONENAND_REG_WP_STATUS);
Kyungmin Park08f782b2006-11-16 11:29:39 +09002632 if (!(status & wp_status_mask))
Amul Kumar Saha297758f2009-10-02 16:59:11 +05302633 printk(KERN_ERR "%s: block = %d, wp status = 0x%x\n",
2634 __func__, block, status);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002635 }
Thomas Gleixnerd5c5e782005-11-07 11:15:51 +00002636
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01002637 return 0;
2638}
2639
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002640/**
Kyungmin Park08f782b2006-11-16 11:29:39 +09002641 * onenand_lock - [MTD Interface] Lock block(s)
2642 * @param mtd MTD device structure
2643 * @param ofs offset relative to mtd start
2644 * @param len number of bytes to unlock
2645 *
2646 * Lock one or more blocks
2647 */
Adrian Hunter69423d92008-12-10 13:37:21 +00002648static int onenand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
Kyungmin Park08f782b2006-11-16 11:29:39 +09002649{
Adrian Hunter34627f02007-10-12 10:19:26 +03002650 int ret;
2651
2652 onenand_get_device(mtd, FL_LOCKING);
2653 ret = onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_LOCK);
2654 onenand_release_device(mtd);
2655 return ret;
Kyungmin Park08f782b2006-11-16 11:29:39 +09002656}
2657
Kyungmin Park08f782b2006-11-16 11:29:39 +09002658/**
2659 * onenand_unlock - [MTD Interface] Unlock block(s)
2660 * @param mtd MTD device structure
2661 * @param ofs offset relative to mtd start
2662 * @param len number of bytes to unlock
2663 *
2664 * Unlock one or more blocks
2665 */
Adrian Hunter69423d92008-12-10 13:37:21 +00002666static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
Kyungmin Park08f782b2006-11-16 11:29:39 +09002667{
Adrian Hunter34627f02007-10-12 10:19:26 +03002668 int ret;
2669
2670 onenand_get_device(mtd, FL_LOCKING);
2671 ret = onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_UNLOCK);
2672 onenand_release_device(mtd);
2673 return ret;
Kyungmin Park08f782b2006-11-16 11:29:39 +09002674}
2675
2676/**
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002677 * onenand_check_lock_status - [OneNAND Interface] Check lock status
2678 * @param this onenand chip data structure
2679 *
2680 * Check lock status
2681 */
Kyungmin Park66a10502008-02-13 15:55:38 +09002682static int onenand_check_lock_status(struct onenand_chip *this)
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002683{
2684 unsigned int value, block, status;
2685 unsigned int end;
2686
2687 end = this->chipsize >> this->erase_shift;
2688 for (block = 0; block < end; block++) {
2689 /* Set block address */
2690 value = onenand_block_address(this, block);
2691 this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1);
2692 /* Select DataRAM for DDP */
2693 value = onenand_bufferram_address(this, block);
2694 this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2);
2695 /* Set start block address */
2696 this->write_word(block, this->base + ONENAND_REG_START_BLOCK_ADDRESS);
2697
2698 /* Check lock status */
2699 status = this->read_word(this->base + ONENAND_REG_WP_STATUS);
Kyungmin Park66a10502008-02-13 15:55:38 +09002700 if (!(status & ONENAND_WP_US)) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05302701 printk(KERN_ERR "%s: block = %d, wp status = 0x%x\n",
2702 __func__, block, status);
Kyungmin Park66a10502008-02-13 15:55:38 +09002703 return 0;
2704 }
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002705 }
Kyungmin Park66a10502008-02-13 15:55:38 +09002706
2707 return 1;
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002708}
2709
2710/**
2711 * onenand_unlock_all - [OneNAND Interface] unlock all blocks
2712 * @param mtd MTD device structure
2713 *
2714 * Unlock all blocks
2715 */
Kyungmin Park66a10502008-02-13 15:55:38 +09002716static void onenand_unlock_all(struct mtd_info *mtd)
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002717{
2718 struct onenand_chip *this = mtd->priv;
Kyungmin Park66a10502008-02-13 15:55:38 +09002719 loff_t ofs = 0;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002720 loff_t len = mtd->size;
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002721
2722 if (this->options & ONENAND_HAS_UNLOCK_ALL) {
Kyungmin Park10b7a2b2007-01-12 05:45:34 +09002723 /* Set start block address */
2724 this->write_word(0, this->base + ONENAND_REG_START_BLOCK_ADDRESS);
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002725 /* Write unlock command */
2726 this->command(mtd, ONENAND_CMD_UNLOCK_ALL, 0, 0);
2727
2728 /* There's no return value */
Kyungmin Park08f782b2006-11-16 11:29:39 +09002729 this->wait(mtd, FL_LOCKING);
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002730
2731 /* Sanity check */
2732 while (this->read_word(this->base + ONENAND_REG_CTRL_STATUS)
2733 & ONENAND_CTRL_ONGO)
2734 continue;
2735
Kyungmin Park31bb9992009-05-12 13:46:57 -07002736 /* Don't check lock status */
2737 if (this->options & ONENAND_SKIP_UNLOCK_CHECK)
2738 return;
2739
Kyungmin Park66a10502008-02-13 15:55:38 +09002740 /* Check lock status */
2741 if (onenand_check_lock_status(this))
2742 return;
2743
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002744 /* Workaround for all block unlock in DDP */
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002745 if (ONENAND_IS_DDP(this) && !FLEXONENAND(this)) {
Kyungmin Park66a10502008-02-13 15:55:38 +09002746 /* All blocks on another chip */
2747 ofs = this->chipsize >> 1;
2748 len = this->chipsize >> 1;
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002749 }
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002750 }
2751
Kyungmin Park66a10502008-02-13 15:55:38 +09002752 onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_UNLOCK);
Kyungmin Park28b79ff2006-09-26 09:45:28 +00002753}
2754
Kyungmin Park493c6462006-05-12 17:03:07 +03002755#ifdef CONFIG_MTD_ONENAND_OTP
2756
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05302757/**
2758 * onenand_otp_command - Send OTP specific command to OneNAND device
2759 * @param mtd MTD device structure
2760 * @param cmd the command to be sent
2761 * @param addr offset to read from or write to
2762 * @param len number of bytes to read or write
2763 */
2764static int onenand_otp_command(struct mtd_info *mtd, int cmd, loff_t addr,
2765 size_t len)
2766{
2767 struct onenand_chip *this = mtd->priv;
2768 int value, block, page;
2769
2770 /* Address translation */
2771 switch (cmd) {
2772 case ONENAND_CMD_OTP_ACCESS:
2773 block = (int) (addr >> this->erase_shift);
2774 page = -1;
2775 break;
2776
2777 default:
2778 block = (int) (addr >> this->erase_shift);
2779 page = (int) (addr >> this->page_shift);
2780
2781 if (ONENAND_IS_2PLANE(this)) {
2782 /* Make the even block number */
2783 block &= ~1;
2784 /* Is it the odd plane? */
2785 if (addr & this->writesize)
2786 block++;
2787 page >>= 1;
2788 }
2789 page &= this->page_mask;
2790 break;
2791 }
2792
2793 if (block != -1) {
2794 /* Write 'DFS, FBA' of Flash */
2795 value = onenand_block_address(this, block);
2796 this->write_word(value, this->base +
2797 ONENAND_REG_START_ADDRESS1);
2798 }
2799
2800 if (page != -1) {
2801 /* Now we use page size operation */
2802 int sectors = 4, count = 4;
2803 int dataram;
2804
2805 switch (cmd) {
2806 default:
2807 if (ONENAND_IS_2PLANE(this) && cmd == ONENAND_CMD_PROG)
2808 cmd = ONENAND_CMD_2X_PROG;
2809 dataram = ONENAND_CURRENT_BUFFERRAM(this);
2810 break;
2811 }
2812
2813 /* Write 'FPA, FSA' of Flash */
2814 value = onenand_page_address(page, sectors);
2815 this->write_word(value, this->base +
2816 ONENAND_REG_START_ADDRESS8);
2817
2818 /* Write 'BSA, BSC' of DataRAM */
2819 value = onenand_buffer_address(dataram, sectors, count);
2820 this->write_word(value, this->base + ONENAND_REG_START_BUFFER);
2821 }
2822
2823 /* Interrupt clear */
2824 this->write_word(ONENAND_INT_CLEAR, this->base + ONENAND_REG_INTERRUPT);
2825
2826 /* Write command */
2827 this->write_word(cmd, this->base + ONENAND_REG_COMMAND);
2828
2829 return 0;
2830}
2831
2832/**
Brian Norris7854d3f2011-06-23 14:12:08 -07002833 * onenand_otp_write_oob_nolock - [INTERN] OneNAND write out-of-band, specific to OTP
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05302834 * @param mtd MTD device structure
2835 * @param to offset to write to
2836 * @param len number of bytes to write
2837 * @param retlen pointer to variable to store the number of written bytes
2838 * @param buf the data to write
2839 *
2840 * OneNAND write out-of-band only for OTP
2841 */
2842static int onenand_otp_write_oob_nolock(struct mtd_info *mtd, loff_t to,
2843 struct mtd_oob_ops *ops)
2844{
2845 struct onenand_chip *this = mtd->priv;
2846 int column, ret = 0, oobsize;
2847 int written = 0;
2848 u_char *oobbuf;
2849 size_t len = ops->ooblen;
2850 const u_char *buf = ops->oobbuf;
2851 int block, value, status;
2852
2853 to += ops->ooboffs;
2854
2855 /* Initialize retlen, in case of early exit */
2856 ops->oobretlen = 0;
2857
2858 oobsize = mtd->oobsize;
2859
2860 column = to & (mtd->oobsize - 1);
2861
2862 oobbuf = this->oob_buf;
2863
2864 /* Loop until all data write */
2865 while (written < len) {
2866 int thislen = min_t(int, oobsize, len - written);
2867
2868 cond_resched();
2869
2870 block = (int) (to >> this->erase_shift);
2871 /*
2872 * Write 'DFS, FBA' of Flash
2873 * Add: F100h DQ=DFS, FBA
2874 */
2875
2876 value = onenand_block_address(this, block);
2877 this->write_word(value, this->base +
2878 ONENAND_REG_START_ADDRESS1);
2879
2880 /*
2881 * Select DataRAM for DDP
2882 * Add: F101h DQ=DBS
2883 */
2884
2885 value = onenand_bufferram_address(this, block);
2886 this->write_word(value, this->base +
2887 ONENAND_REG_START_ADDRESS2);
2888 ONENAND_SET_NEXT_BUFFERRAM(this);
2889
2890 /*
2891 * Enter OTP access mode
2892 */
2893 this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0);
2894 this->wait(mtd, FL_OTPING);
2895
2896 /* We send data to spare ram with oobsize
2897 * to prevent byte access */
2898 memcpy(oobbuf + column, buf, thislen);
2899
2900 /*
2901 * Write Data into DataRAM
2902 * Add: 8th Word
2903 * in sector0/spare/page0
2904 * DQ=XXFCh
2905 */
2906 this->write_bufferram(mtd, ONENAND_SPARERAM,
2907 oobbuf, 0, mtd->oobsize);
2908
2909 onenand_otp_command(mtd, ONENAND_CMD_PROGOOB, to, mtd->oobsize);
2910 onenand_update_bufferram(mtd, to, 0);
2911 if (ONENAND_IS_2PLANE(this)) {
2912 ONENAND_SET_BUFFERRAM1(this);
2913 onenand_update_bufferram(mtd, to + this->writesize, 0);
2914 }
2915
2916 ret = this->wait(mtd, FL_WRITING);
2917 if (ret) {
2918 printk(KERN_ERR "%s: write failed %d\n", __func__, ret);
2919 break;
2920 }
2921
2922 /* Exit OTP access mode */
2923 this->command(mtd, ONENAND_CMD_RESET, 0, 0);
2924 this->wait(mtd, FL_RESETING);
2925
2926 status = this->read_word(this->base + ONENAND_REG_CTRL_STATUS);
2927 status &= 0x60;
2928
2929 if (status == 0x60) {
2930 printk(KERN_DEBUG "\nBLOCK\tSTATUS\n");
2931 printk(KERN_DEBUG "1st Block\tLOCKED\n");
2932 printk(KERN_DEBUG "OTP Block\tLOCKED\n");
2933 } else if (status == 0x20) {
2934 printk(KERN_DEBUG "\nBLOCK\tSTATUS\n");
2935 printk(KERN_DEBUG "1st Block\tLOCKED\n");
2936 printk(KERN_DEBUG "OTP Block\tUN-LOCKED\n");
2937 } else if (status == 0x40) {
2938 printk(KERN_DEBUG "\nBLOCK\tSTATUS\n");
2939 printk(KERN_DEBUG "1st Block\tUN-LOCKED\n");
2940 printk(KERN_DEBUG "OTP Block\tLOCKED\n");
2941 } else {
2942 printk(KERN_DEBUG "Reboot to check\n");
2943 }
2944
2945 written += thislen;
2946 if (written == len)
2947 break;
2948
2949 to += mtd->writesize;
2950 buf += thislen;
2951 column = 0;
2952 }
2953
2954 ops->oobretlen = written;
2955
2956 return ret;
2957}
2958
Mika Korhonen492e1502009-06-09 21:52:35 +03002959/* Internal OTP operation */
Kyungmin Park493c6462006-05-12 17:03:07 +03002960typedef int (*otp_op_t)(struct mtd_info *mtd, loff_t form, size_t len,
2961 size_t *retlen, u_char *buf);
2962
2963/**
2964 * do_otp_read - [DEFAULT] Read OTP block area
2965 * @param mtd MTD device structure
2966 * @param from The offset to read
2967 * @param len number of bytes to read
2968 * @param retlen pointer to variable to store the number of readbytes
2969 * @param buf the databuffer to put/get data
2970 *
2971 * Read OTP block area.
2972 */
2973static int do_otp_read(struct mtd_info *mtd, loff_t from, size_t len,
2974 size_t *retlen, u_char *buf)
2975{
2976 struct onenand_chip *this = mtd->priv;
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03002977 struct mtd_oob_ops ops = {
2978 .len = len,
2979 .ooblen = 0,
2980 .datbuf = buf,
2981 .oobbuf = NULL,
2982 };
Kyungmin Park493c6462006-05-12 17:03:07 +03002983 int ret;
2984
2985 /* Enter OTP access mode */
2986 this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0);
2987 this->wait(mtd, FL_OTPING);
2988
Kyungmin Park8a8f6322010-12-02 09:24:16 +09002989 ret = ONENAND_IS_4KB_PAGE(this) ?
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07002990 onenand_mlc_read_ops_nolock(mtd, from, &ops) :
2991 onenand_read_ops_nolock(mtd, from, &ops);
Kyungmin Park493c6462006-05-12 17:03:07 +03002992
2993 /* Exit OTP access mode */
2994 this->command(mtd, ONENAND_CMD_RESET, 0, 0);
2995 this->wait(mtd, FL_RESETING);
2996
2997 return ret;
2998}
2999
3000/**
3001 * do_otp_write - [DEFAULT] Write OTP block area
3002 * @param mtd MTD device structure
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03003003 * @param to The offset to write
Kyungmin Park493c6462006-05-12 17:03:07 +03003004 * @param len number of bytes to write
3005 * @param retlen pointer to variable to store the number of write bytes
3006 * @param buf the databuffer to put/get data
3007 *
3008 * Write OTP block area.
3009 */
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03003010static int do_otp_write(struct mtd_info *mtd, loff_t to, size_t len,
Kyungmin Park493c6462006-05-12 17:03:07 +03003011 size_t *retlen, u_char *buf)
3012{
3013 struct onenand_chip *this = mtd->priv;
3014 unsigned char *pbuf = buf;
3015 int ret;
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03003016 struct mtd_oob_ops ops;
Kyungmin Park493c6462006-05-12 17:03:07 +03003017
3018 /* Force buffer page aligned */
Joern Engel28318772006-05-22 23:18:05 +02003019 if (len < mtd->writesize) {
Kyungmin Park493c6462006-05-12 17:03:07 +03003020 memcpy(this->page_buf, buf, len);
Joern Engel28318772006-05-22 23:18:05 +02003021 memset(this->page_buf + len, 0xff, mtd->writesize - len);
Kyungmin Park493c6462006-05-12 17:03:07 +03003022 pbuf = this->page_buf;
Joern Engel28318772006-05-22 23:18:05 +02003023 len = mtd->writesize;
Kyungmin Park493c6462006-05-12 17:03:07 +03003024 }
3025
3026 /* Enter OTP access mode */
3027 this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0);
3028 this->wait(mtd, FL_OTPING);
3029
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03003030 ops.len = len;
3031 ops.ooblen = 0;
Kyungmin Park14370852007-10-10 13:48:14 +09003032 ops.datbuf = pbuf;
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03003033 ops.oobbuf = NULL;
3034 ret = onenand_write_ops_nolock(mtd, to, &ops);
3035 *retlen = ops.retlen;
Kyungmin Park493c6462006-05-12 17:03:07 +03003036
3037 /* Exit OTP access mode */
3038 this->command(mtd, ONENAND_CMD_RESET, 0, 0);
3039 this->wait(mtd, FL_RESETING);
3040
3041 return ret;
3042}
3043
3044/**
3045 * do_otp_lock - [DEFAULT] Lock OTP block area
3046 * @param mtd MTD device structure
3047 * @param from The offset to lock
3048 * @param len number of bytes to lock
3049 * @param retlen pointer to variable to store the number of lock bytes
3050 * @param buf the databuffer to put/get data
3051 *
3052 * Lock OTP block area.
3053 */
3054static int do_otp_lock(struct mtd_info *mtd, loff_t from, size_t len,
3055 size_t *retlen, u_char *buf)
3056{
3057 struct onenand_chip *this = mtd->priv;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003058 struct mtd_oob_ops ops;
Kyungmin Park493c6462006-05-12 17:03:07 +03003059 int ret;
3060
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003061 if (FLEXONENAND(this)) {
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05303062
3063 /* Enter OTP access mode */
3064 this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0);
3065 this->wait(mtd, FL_OTPING);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003066 /*
3067 * For Flex-OneNAND, we write lock mark to 1st word of sector 4 of
3068 * main area of page 49.
3069 */
3070 ops.len = mtd->writesize;
3071 ops.ooblen = 0;
3072 ops.datbuf = buf;
3073 ops.oobbuf = NULL;
3074 ret = onenand_write_ops_nolock(mtd, mtd->writesize * 49, &ops);
3075 *retlen = ops.retlen;
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05303076
3077 /* Exit OTP access mode */
3078 this->command(mtd, ONENAND_CMD_RESET, 0, 0);
3079 this->wait(mtd, FL_RESETING);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003080 } else {
Brian Norris0612b9d2011-08-30 18:45:40 -07003081 ops.mode = MTD_OPS_PLACE_OOB;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003082 ops.ooblen = len;
3083 ops.oobbuf = buf;
3084 ops.ooboffs = 0;
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05303085 ret = onenand_otp_write_oob_nolock(mtd, from, &ops);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003086 *retlen = ops.oobretlen;
3087 }
Kyungmin Park493c6462006-05-12 17:03:07 +03003088
Kyungmin Park493c6462006-05-12 17:03:07 +03003089 return ret;
3090}
3091
3092/**
3093 * onenand_otp_walk - [DEFAULT] Handle OTP operation
3094 * @param mtd MTD device structure
3095 * @param from The offset to read/write
3096 * @param len number of bytes to read/write
3097 * @param retlen pointer to variable to store the number of read bytes
3098 * @param buf the databuffer to put/get data
3099 * @param action do given action
3100 * @param mode specify user and factory
3101 *
3102 * Handle OTP operation.
3103 */
3104static int onenand_otp_walk(struct mtd_info *mtd, loff_t from, size_t len,
3105 size_t *retlen, u_char *buf,
3106 otp_op_t action, int mode)
3107{
3108 struct onenand_chip *this = mtd->priv;
3109 int otp_pages;
3110 int density;
3111 int ret = 0;
3112
3113 *retlen = 0;
3114
Kyungmin Parke71f04f2007-12-11 11:23:45 +09003115 density = onenand_get_density(this->device_id);
Kyungmin Park493c6462006-05-12 17:03:07 +03003116 if (density < ONENAND_DEVICE_DENSITY_512Mb)
3117 otp_pages = 20;
3118 else
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05303119 otp_pages = 50;
Kyungmin Park493c6462006-05-12 17:03:07 +03003120
3121 if (mode == MTD_OTP_FACTORY) {
Joern Engel28318772006-05-22 23:18:05 +02003122 from += mtd->writesize * otp_pages;
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05303123 otp_pages = ONENAND_PAGES_PER_BLOCK - otp_pages;
Kyungmin Park493c6462006-05-12 17:03:07 +03003124 }
3125
3126 /* Check User/Factory boundary */
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05303127 if (mode == MTD_OTP_USER) {
Roel Kluin0a032a42009-12-16 01:37:17 +01003128 if (mtd->writesize * otp_pages < from + len)
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05303129 return 0;
3130 } else {
Roel Kluin0a032a42009-12-16 01:37:17 +01003131 if (mtd->writesize * otp_pages < len)
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05303132 return 0;
3133 }
Kyungmin Park493c6462006-05-12 17:03:07 +03003134
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03003135 onenand_get_device(mtd, FL_OTPING);
Kyungmin Park493c6462006-05-12 17:03:07 +03003136 while (len > 0 && otp_pages > 0) {
3137 if (!action) { /* OTP Info functions */
3138 struct otp_info *otpinfo;
3139
3140 len -= sizeof(struct otp_info);
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03003141 if (len <= 0) {
3142 ret = -ENOSPC;
3143 break;
3144 }
Kyungmin Park493c6462006-05-12 17:03:07 +03003145
3146 otpinfo = (struct otp_info *) buf;
3147 otpinfo->start = from;
Joern Engel28318772006-05-22 23:18:05 +02003148 otpinfo->length = mtd->writesize;
Kyungmin Park493c6462006-05-12 17:03:07 +03003149 otpinfo->locked = 0;
3150
Joern Engel28318772006-05-22 23:18:05 +02003151 from += mtd->writesize;
Kyungmin Park493c6462006-05-12 17:03:07 +03003152 buf += sizeof(struct otp_info);
3153 *retlen += sizeof(struct otp_info);
3154 } else {
3155 size_t tmp_retlen;
Kyungmin Park493c6462006-05-12 17:03:07 +03003156
3157 ret = action(mtd, from, len, &tmp_retlen, buf);
3158
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05303159 buf += tmp_retlen;
3160 len -= tmp_retlen;
3161 *retlen += tmp_retlen;
Kyungmin Park493c6462006-05-12 17:03:07 +03003162
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03003163 if (ret)
3164 break;
Kyungmin Park493c6462006-05-12 17:03:07 +03003165 }
3166 otp_pages--;
3167 }
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03003168 onenand_release_device(mtd);
Kyungmin Park493c6462006-05-12 17:03:07 +03003169
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03003170 return ret;
Kyungmin Park493c6462006-05-12 17:03:07 +03003171}
3172
3173/**
3174 * onenand_get_fact_prot_info - [MTD Interface] Read factory OTP info
3175 * @param mtd MTD device structure
Kyungmin Park493c6462006-05-12 17:03:07 +03003176 * @param len number of bytes to read
Christian Riesch4b78fc42014-01-28 09:29:44 +01003177 * @param retlen pointer to variable to store the number of read bytes
3178 * @param buf the databuffer to put/get data
Kyungmin Park493c6462006-05-12 17:03:07 +03003179 *
3180 * Read factory OTP info.
3181 */
Christian Riesch4b78fc42014-01-28 09:29:44 +01003182static int onenand_get_fact_prot_info(struct mtd_info *mtd, size_t len,
3183 size_t *retlen, struct otp_info *buf)
Kyungmin Park493c6462006-05-12 17:03:07 +03003184{
Christian Riesch4b78fc42014-01-28 09:29:44 +01003185 return onenand_otp_walk(mtd, 0, len, retlen, (u_char *) buf, NULL,
3186 MTD_OTP_FACTORY);
Kyungmin Park493c6462006-05-12 17:03:07 +03003187}
3188
3189/**
3190 * onenand_read_fact_prot_reg - [MTD Interface] Read factory OTP area
3191 * @param mtd MTD device structure
3192 * @param from The offset to read
3193 * @param len number of bytes to read
3194 * @param retlen pointer to variable to store the number of read bytes
3195 * @param buf the databuffer to put/get data
3196 *
3197 * Read factory OTP area.
3198 */
3199static int onenand_read_fact_prot_reg(struct mtd_info *mtd, loff_t from,
3200 size_t len, size_t *retlen, u_char *buf)
3201{
3202 return onenand_otp_walk(mtd, from, len, retlen, buf, do_otp_read, MTD_OTP_FACTORY);
3203}
3204
3205/**
3206 * onenand_get_user_prot_info - [MTD Interface] Read user OTP info
3207 * @param mtd MTD device structure
Christian Riesch4b78fc42014-01-28 09:29:44 +01003208 * @param retlen pointer to variable to store the number of read bytes
Kyungmin Park493c6462006-05-12 17:03:07 +03003209 * @param len number of bytes to read
Christian Riesch4b78fc42014-01-28 09:29:44 +01003210 * @param buf the databuffer to put/get data
Kyungmin Park493c6462006-05-12 17:03:07 +03003211 *
3212 * Read user OTP info.
3213 */
Christian Riesch4b78fc42014-01-28 09:29:44 +01003214static int onenand_get_user_prot_info(struct mtd_info *mtd, size_t len,
3215 size_t *retlen, struct otp_info *buf)
Kyungmin Park493c6462006-05-12 17:03:07 +03003216{
Christian Riesch4b78fc42014-01-28 09:29:44 +01003217 return onenand_otp_walk(mtd, 0, len, retlen, (u_char *) buf, NULL,
3218 MTD_OTP_USER);
Kyungmin Park493c6462006-05-12 17:03:07 +03003219}
3220
3221/**
3222 * onenand_read_user_prot_reg - [MTD Interface] Read user OTP area
3223 * @param mtd MTD device structure
3224 * @param from The offset to read
3225 * @param len number of bytes to read
3226 * @param retlen pointer to variable to store the number of read bytes
3227 * @param buf the databuffer to put/get data
3228 *
3229 * Read user OTP area.
3230 */
3231static int onenand_read_user_prot_reg(struct mtd_info *mtd, loff_t from,
3232 size_t len, size_t *retlen, u_char *buf)
3233{
3234 return onenand_otp_walk(mtd, from, len, retlen, buf, do_otp_read, MTD_OTP_USER);
3235}
3236
3237/**
3238 * onenand_write_user_prot_reg - [MTD Interface] Write user OTP area
3239 * @param mtd MTD device structure
3240 * @param from The offset to write
3241 * @param len number of bytes to write
3242 * @param retlen pointer to variable to store the number of write bytes
3243 * @param buf the databuffer to put/get data
3244 *
3245 * Write user OTP area.
3246 */
3247static int onenand_write_user_prot_reg(struct mtd_info *mtd, loff_t from,
3248 size_t len, size_t *retlen, u_char *buf)
3249{
3250 return onenand_otp_walk(mtd, from, len, retlen, buf, do_otp_write, MTD_OTP_USER);
3251}
3252
3253/**
3254 * onenand_lock_user_prot_reg - [MTD Interface] Lock user OTP area
3255 * @param mtd MTD device structure
3256 * @param from The offset to lock
3257 * @param len number of bytes to unlock
3258 *
3259 * Write lock mark on spare area in page 0 in OTP block
3260 */
3261static int onenand_lock_user_prot_reg(struct mtd_info *mtd, loff_t from,
3262 size_t len)
3263{
Kyungmin Park69d79182007-12-14 14:47:21 +09003264 struct onenand_chip *this = mtd->priv;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003265 u_char *buf = FLEXONENAND(this) ? this->page_buf : this->oob_buf;
Kyungmin Park493c6462006-05-12 17:03:07 +03003266 size_t retlen;
3267 int ret;
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05303268 unsigned int otp_lock_offset = ONENAND_OTP_LOCK_OFFSET;
Kyungmin Park493c6462006-05-12 17:03:07 +03003269
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003270 memset(buf, 0xff, FLEXONENAND(this) ? this->writesize
3271 : mtd->oobsize);
Kyungmin Park493c6462006-05-12 17:03:07 +03003272 /*
Kyungmin Park493c6462006-05-12 17:03:07 +03003273 * Write lock mark to 8th word of sector0 of page0 of the spare0.
3274 * We write 16 bytes spare area instead of 2 bytes.
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003275 * For Flex-OneNAND, we write lock mark to 1st word of sector 4 of
3276 * main area of page 49.
Kyungmin Park493c6462006-05-12 17:03:07 +03003277 */
Kyungmin Park493c6462006-05-12 17:03:07 +03003278
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003279 from = 0;
3280 len = FLEXONENAND(this) ? mtd->writesize : 16;
3281
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05303282 /*
3283 * Note: OTP lock operation
3284 * OTP block : 0xXXFC XX 1111 1100
3285 * 1st block : 0xXXF3 (If chip support) XX 1111 0011
3286 * Both : 0xXXF0 (If chip support) XX 1111 0000
3287 */
3288 if (FLEXONENAND(this))
3289 otp_lock_offset = FLEXONENAND_OTP_LOCK_OFFSET;
3290
3291 /* ONENAND_OTP_AREA | ONENAND_OTP_BLOCK0 | ONENAND_OTP_AREA_BLOCK0 */
3292 if (otp == 1)
3293 buf[otp_lock_offset] = 0xFC;
3294 else if (otp == 2)
3295 buf[otp_lock_offset] = 0xF3;
3296 else if (otp == 3)
3297 buf[otp_lock_offset] = 0xF0;
3298 else if (otp != 0)
3299 printk(KERN_DEBUG "[OneNAND] Invalid option selected for OTP\n");
3300
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003301 ret = onenand_otp_walk(mtd, from, len, &retlen, buf, do_otp_lock, MTD_OTP_USER);
Kyungmin Park493c6462006-05-12 17:03:07 +03003302
3303 return ret ? : retlen;
3304}
Amul Kumar Saha3cf60252009-10-21 17:00:05 +05303305
Kyungmin Park493c6462006-05-12 17:03:07 +03003306#endif /* CONFIG_MTD_ONENAND_OTP */
3307
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003308/**
Kyungmin Park75384b02007-01-18 11:10:57 +09003309 * onenand_check_features - Check and set OneNAND features
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003310 * @param mtd MTD data structure
3311 *
Kyungmin Park75384b02007-01-18 11:10:57 +09003312 * Check and set OneNAND features
3313 * - lock scheme
Kyungmin Parkee9745f2007-06-30 13:57:49 +09003314 * - two plane
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003315 */
Kyungmin Park75384b02007-01-18 11:10:57 +09003316static void onenand_check_features(struct mtd_info *mtd)
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003317{
3318 struct onenand_chip *this = mtd->priv;
Roman Tereshonkovedb44b92010-10-11 14:47:32 +03003319 unsigned int density, process, numbufs;
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003320
3321 /* Lock scheme depends on density and process */
Kyungmin Parke71f04f2007-12-11 11:23:45 +09003322 density = onenand_get_density(this->device_id);
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003323 process = this->version_id >> ONENAND_VERSION_PROCESS_SHIFT;
Roman Tereshonkovedb44b92010-10-11 14:47:32 +03003324 numbufs = this->read_word(this->base + ONENAND_REG_NUM_BUFFERS) >> 8;
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003325
3326 /* Lock scheme */
Kyungmin Parkee9745f2007-06-30 13:57:49 +09003327 switch (density) {
3328 case ONENAND_DEVICE_DENSITY_4Gb:
Kyungmin Park6a88c472010-04-28 17:46:45 +02003329 if (ONENAND_IS_DDP(this))
3330 this->options |= ONENAND_HAS_2PLANE;
Roman Tereshonkovac80dac2010-11-03 12:55:21 +02003331 else if (numbufs == 1) {
Kyungmin Park6a88c472010-04-28 17:46:45 +02003332 this->options |= ONENAND_HAS_4KB_PAGE;
Roman Tereshonkovac80dac2010-11-03 12:55:21 +02003333 this->options |= ONENAND_HAS_CACHE_PROGRAM;
Kyungmin Parke1c10242011-06-22 14:16:49 +09003334 /*
3335 * There are two different 4KiB pagesize chips
3336 * and no way to detect it by H/W config values.
3337 *
3338 * To detect the correct NOP for each chips,
3339 * It should check the version ID as workaround.
3340 *
3341 * Now it has as following
3342 * KFM4G16Q4M has NOP 4 with version ID 0x0131
3343 * KFM4G16Q5M has NOP 1 with versoin ID 0x013e
3344 */
3345 if ((this->version_id & 0xf) == 0xe)
3346 this->options |= ONENAND_HAS_NOP_1;
Roman Tereshonkovac80dac2010-11-03 12:55:21 +02003347 }
Kyungmin Parkee9745f2007-06-30 13:57:49 +09003348
3349 case ONENAND_DEVICE_DENSITY_2Gb:
Mika Korhonen492e1502009-06-09 21:52:35 +03003350 /* 2Gb DDP does not have 2 plane */
Kyungmin Parkee9745f2007-06-30 13:57:49 +09003351 if (!ONENAND_IS_DDP(this))
3352 this->options |= ONENAND_HAS_2PLANE;
3353 this->options |= ONENAND_HAS_UNLOCK_ALL;
3354
3355 case ONENAND_DEVICE_DENSITY_1Gb:
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003356 /* A-Die has all block unlock */
Kyungmin Parkee9745f2007-06-30 13:57:49 +09003357 if (process)
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003358 this->options |= ONENAND_HAS_UNLOCK_ALL;
Kyungmin Parkee9745f2007-06-30 13:57:49 +09003359 break;
3360
3361 default:
3362 /* Some OneNAND has continuous lock scheme */
3363 if (!process)
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003364 this->options |= ONENAND_HAS_CONT_LOCK;
Kyungmin Parkee9745f2007-06-30 13:57:49 +09003365 break;
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003366 }
Kyungmin Parkee9745f2007-06-30 13:57:49 +09003367
Kyungmin Park8a8f6322010-12-02 09:24:16 +09003368 /* The MLC has 4KiB pagesize. */
3369 if (ONENAND_IS_MLC(this))
3370 this->options |= ONENAND_HAS_4KB_PAGE;
3371
3372 if (ONENAND_IS_4KB_PAGE(this))
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003373 this->options &= ~ONENAND_HAS_2PLANE;
3374
3375 if (FLEXONENAND(this)) {
3376 this->options &= ~ONENAND_HAS_CONT_LOCK;
3377 this->options |= ONENAND_HAS_UNLOCK_ALL;
3378 }
3379
Kyungmin Parkee9745f2007-06-30 13:57:49 +09003380 if (this->options & ONENAND_HAS_CONT_LOCK)
3381 printk(KERN_DEBUG "Lock scheme is Continuous Lock\n");
3382 if (this->options & ONENAND_HAS_UNLOCK_ALL)
3383 printk(KERN_DEBUG "Chip support all block unlock\n");
3384 if (this->options & ONENAND_HAS_2PLANE)
3385 printk(KERN_DEBUG "Chip has 2 plane\n");
Kyungmin Park6a88c472010-04-28 17:46:45 +02003386 if (this->options & ONENAND_HAS_4KB_PAGE)
3387 printk(KERN_DEBUG "Chip has 4KiB pagesize\n");
Roman Tereshonkovac80dac2010-11-03 12:55:21 +02003388 if (this->options & ONENAND_HAS_CACHE_PROGRAM)
3389 printk(KERN_DEBUG "Chip has cache program feature\n");
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003390}
3391
3392/**
Kyungmin Parke3da8062007-02-15 09:36:39 +09003393 * onenand_print_device_info - Print device & version ID
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003394 * @param device device ID
Kyungmin Parke3da8062007-02-15 09:36:39 +09003395 * @param version version ID
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003396 *
Kyungmin Parke3da8062007-02-15 09:36:39 +09003397 * Print device & version ID
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003398 */
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003399static void onenand_print_device_info(int device, int version)
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003400{
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003401 int vcc, demuxed, ddp, density, flexonenand;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003402
3403 vcc = device & ONENAND_DEVICE_VCC_MASK;
3404 demuxed = device & ONENAND_DEVICE_IS_DEMUX;
3405 ddp = device & ONENAND_DEVICE_IS_DDP;
Kyungmin Parke71f04f2007-12-11 11:23:45 +09003406 density = onenand_get_density(device);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003407 flexonenand = device & DEVICE_IS_FLEXONENAND;
3408 printk(KERN_INFO "%s%sOneNAND%s %dMB %sV 16-bit (0x%02x)\n",
3409 demuxed ? "" : "Muxed ",
3410 flexonenand ? "Flex-" : "",
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003411 ddp ? "(DDP)" : "",
3412 (16 << density),
3413 vcc ? "2.65/3.3" : "1.8",
3414 device);
Artem Bityutskiy49dc08e2007-09-21 19:35:21 +03003415 printk(KERN_INFO "OneNAND version = 0x%04x\n", version);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003416}
3417
3418static const struct onenand_manufacturers onenand_manuf_ids[] = {
3419 {ONENAND_MFR_SAMSUNG, "Samsung"},
Adrian Hunteree8f3762009-05-05 11:04:19 +03003420 {ONENAND_MFR_NUMONYX, "Numonyx"},
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003421};
3422
3423/**
3424 * onenand_check_maf - Check manufacturer ID
3425 * @param manuf manufacturer ID
3426 *
3427 * Check manufacturer ID
3428 */
3429static int onenand_check_maf(int manuf)
3430{
Kyungmin Park37b1cc32005-12-16 11:17:29 +09003431 int size = ARRAY_SIZE(onenand_manuf_ids);
3432 char *name;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003433 int i;
3434
Kyungmin Park37b1cc32005-12-16 11:17:29 +09003435 for (i = 0; i < size; i++)
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003436 if (manuf == onenand_manuf_ids[i].id)
3437 break;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003438
Kyungmin Park37b1cc32005-12-16 11:17:29 +09003439 if (i < size)
3440 name = onenand_manuf_ids[i].name;
3441 else
3442 name = "Unknown";
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003443
Kyungmin Park37b1cc32005-12-16 11:17:29 +09003444 printk(KERN_DEBUG "OneNAND Manufacturer: %s (0x%0x)\n", name, manuf);
3445
3446 return (i == size);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003447}
3448
3449/**
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003450* flexonenand_get_boundary - Reads the SLC boundary
3451* @param onenand_info - onenand info structure
3452**/
3453static int flexonenand_get_boundary(struct mtd_info *mtd)
3454{
3455 struct onenand_chip *this = mtd->priv;
3456 unsigned die, bdry;
Brian Norris6b7368c2013-08-27 18:01:19 -07003457 int syscfg, locked;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003458
3459 /* Disable ECC */
3460 syscfg = this->read_word(this->base + ONENAND_REG_SYS_CFG1);
3461 this->write_word((syscfg | 0x0100), this->base + ONENAND_REG_SYS_CFG1);
3462
3463 for (die = 0; die < this->dies; die++) {
3464 this->command(mtd, FLEXONENAND_CMD_PI_ACCESS, die, 0);
3465 this->wait(mtd, FL_SYNCING);
3466
3467 this->command(mtd, FLEXONENAND_CMD_READ_PI, die, 0);
Brian Norris6b7368c2013-08-27 18:01:19 -07003468 this->wait(mtd, FL_READING);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003469
3470 bdry = this->read_word(this->base + ONENAND_DATARAM);
3471 if ((bdry >> FLEXONENAND_PI_UNLOCK_SHIFT) == 3)
3472 locked = 0;
3473 else
3474 locked = 1;
3475 this->boundary[die] = bdry & FLEXONENAND_PI_MASK;
3476
3477 this->command(mtd, ONENAND_CMD_RESET, 0, 0);
Brian Norris6b7368c2013-08-27 18:01:19 -07003478 this->wait(mtd, FL_RESETING);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003479
3480 printk(KERN_INFO "Die %d boundary: %d%s\n", die,
3481 this->boundary[die], locked ? "(Locked)" : "(Unlocked)");
3482 }
3483
3484 /* Enable ECC */
3485 this->write_word(syscfg, this->base + ONENAND_REG_SYS_CFG1);
3486 return 0;
3487}
3488
3489/**
3490 * flexonenand_get_size - Fill up fields in onenand_chip and mtd_info
3491 * boundary[], diesize[], mtd->size, mtd->erasesize
3492 * @param mtd - MTD device structure
3493 */
3494static void flexonenand_get_size(struct mtd_info *mtd)
3495{
3496 struct onenand_chip *this = mtd->priv;
3497 int die, i, eraseshift, density;
3498 int blksperdie, maxbdry;
3499 loff_t ofs;
3500
3501 density = onenand_get_density(this->device_id);
3502 blksperdie = ((loff_t)(16 << density) << 20) >> (this->erase_shift);
3503 blksperdie >>= ONENAND_IS_DDP(this) ? 1 : 0;
3504 maxbdry = blksperdie - 1;
3505 eraseshift = this->erase_shift - 1;
3506
3507 mtd->numeraseregions = this->dies << 1;
3508
3509 /* This fills up the device boundary */
3510 flexonenand_get_boundary(mtd);
3511 die = ofs = 0;
3512 i = -1;
3513 for (; die < this->dies; die++) {
3514 if (!die || this->boundary[die-1] != maxbdry) {
3515 i++;
3516 mtd->eraseregions[i].offset = ofs;
3517 mtd->eraseregions[i].erasesize = 1 << eraseshift;
3518 mtd->eraseregions[i].numblocks =
3519 this->boundary[die] + 1;
3520 ofs += mtd->eraseregions[i].numblocks << eraseshift;
3521 eraseshift++;
3522 } else {
3523 mtd->numeraseregions -= 1;
3524 mtd->eraseregions[i].numblocks +=
3525 this->boundary[die] + 1;
3526 ofs += (this->boundary[die] + 1) << (eraseshift - 1);
3527 }
3528 if (this->boundary[die] != maxbdry) {
3529 i++;
3530 mtd->eraseregions[i].offset = ofs;
3531 mtd->eraseregions[i].erasesize = 1 << eraseshift;
3532 mtd->eraseregions[i].numblocks = maxbdry ^
3533 this->boundary[die];
3534 ofs += mtd->eraseregions[i].numblocks << eraseshift;
3535 eraseshift--;
3536 } else
3537 mtd->numeraseregions -= 1;
3538 }
3539
3540 /* Expose MLC erase size except when all blocks are SLC */
3541 mtd->erasesize = 1 << this->erase_shift;
3542 if (mtd->numeraseregions == 1)
3543 mtd->erasesize >>= 1;
3544
3545 printk(KERN_INFO "Device has %d eraseregions\n", mtd->numeraseregions);
3546 for (i = 0; i < mtd->numeraseregions; i++)
3547 printk(KERN_INFO "[offset: 0x%08x, erasesize: 0x%05x,"
3548 " numblocks: %04u]\n",
3549 (unsigned int) mtd->eraseregions[i].offset,
3550 mtd->eraseregions[i].erasesize,
3551 mtd->eraseregions[i].numblocks);
3552
3553 for (die = 0, mtd->size = 0; die < this->dies; die++) {
3554 this->diesize[die] = (loff_t)blksperdie << this->erase_shift;
3555 this->diesize[die] -= (loff_t)(this->boundary[die] + 1)
3556 << (this->erase_shift - 1);
3557 mtd->size += this->diesize[die];
3558 }
3559}
3560
3561/**
3562 * flexonenand_check_blocks_erased - Check if blocks are erased
3563 * @param mtd_info - mtd info structure
3564 * @param start - first erase block to check
3565 * @param end - last erase block to check
3566 *
3567 * Converting an unerased block from MLC to SLC
3568 * causes byte values to change. Since both data and its ECC
3569 * have changed, reads on the block give uncorrectable error.
3570 * This might lead to the block being detected as bad.
3571 *
3572 * Avoid this by ensuring that the block to be converted is
3573 * erased.
3574 */
3575static int flexonenand_check_blocks_erased(struct mtd_info *mtd, int start, int end)
3576{
3577 struct onenand_chip *this = mtd->priv;
3578 int i, ret;
3579 int block;
3580 struct mtd_oob_ops ops = {
Brian Norris0612b9d2011-08-30 18:45:40 -07003581 .mode = MTD_OPS_PLACE_OOB,
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003582 .ooboffs = 0,
3583 .ooblen = mtd->oobsize,
3584 .datbuf = NULL,
3585 .oobbuf = this->oob_buf,
3586 };
3587 loff_t addr;
3588
3589 printk(KERN_DEBUG "Check blocks from %d to %d\n", start, end);
3590
3591 for (block = start; block <= end; block++) {
3592 addr = flexonenand_addr(this, block);
3593 if (onenand_block_isbad_nolock(mtd, addr, 0))
3594 continue;
3595
3596 /*
3597 * Since main area write results in ECC write to spare,
3598 * it is sufficient to check only ECC bytes for change.
3599 */
3600 ret = onenand_read_oob_nolock(mtd, addr, &ops);
3601 if (ret)
3602 return ret;
3603
3604 for (i = 0; i < mtd->oobsize; i++)
3605 if (this->oob_buf[i] != 0xff)
3606 break;
3607
3608 if (i != mtd->oobsize) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05303609 printk(KERN_WARNING "%s: Block %d not erased.\n",
3610 __func__, block);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003611 return 1;
3612 }
3613 }
3614
3615 return 0;
3616}
3617
3618/**
3619 * flexonenand_set_boundary - Writes the SLC boundary
3620 * @param mtd - mtd info structure
3621 */
Sachin Kamat01319502012-09-22 11:42:31 +05303622static int flexonenand_set_boundary(struct mtd_info *mtd, int die,
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003623 int boundary, int lock)
3624{
3625 struct onenand_chip *this = mtd->priv;
3626 int ret, density, blksperdie, old, new, thisboundary;
3627 loff_t addr;
3628
3629 /* Change only once for SDP Flex-OneNAND */
3630 if (die && (!ONENAND_IS_DDP(this)))
3631 return 0;
3632
3633 /* boundary value of -1 indicates no required change */
3634 if (boundary < 0 || boundary == this->boundary[die])
3635 return 0;
3636
3637 density = onenand_get_density(this->device_id);
3638 blksperdie = ((16 << density) << 20) >> this->erase_shift;
3639 blksperdie >>= ONENAND_IS_DDP(this) ? 1 : 0;
3640
3641 if (boundary >= blksperdie) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05303642 printk(KERN_ERR "%s: Invalid boundary value. "
3643 "Boundary not changed.\n", __func__);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003644 return -EINVAL;
3645 }
3646
3647 /* Check if converting blocks are erased */
3648 old = this->boundary[die] + (die * this->density_mask);
3649 new = boundary + (die * this->density_mask);
3650 ret = flexonenand_check_blocks_erased(mtd, min(old, new) + 1, max(old, new));
3651 if (ret) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05303652 printk(KERN_ERR "%s: Please erase blocks "
3653 "before boundary change\n", __func__);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003654 return ret;
3655 }
3656
3657 this->command(mtd, FLEXONENAND_CMD_PI_ACCESS, die, 0);
3658 this->wait(mtd, FL_SYNCING);
3659
3660 /* Check is boundary is locked */
3661 this->command(mtd, FLEXONENAND_CMD_READ_PI, die, 0);
Brian Norris6b7368c2013-08-27 18:01:19 -07003662 this->wait(mtd, FL_READING);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003663
3664 thisboundary = this->read_word(this->base + ONENAND_DATARAM);
3665 if ((thisboundary >> FLEXONENAND_PI_UNLOCK_SHIFT) != 3) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05303666 printk(KERN_ERR "%s: boundary locked\n", __func__);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003667 ret = 1;
3668 goto out;
3669 }
3670
Amul Kumar Saha297758f2009-10-02 16:59:11 +05303671 printk(KERN_INFO "Changing die %d boundary: %d%s\n",
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003672 die, boundary, lock ? "(Locked)" : "(Unlocked)");
3673
3674 addr = die ? this->diesize[0] : 0;
3675
3676 boundary &= FLEXONENAND_PI_MASK;
3677 boundary |= lock ? 0 : (3 << FLEXONENAND_PI_UNLOCK_SHIFT);
3678
3679 this->command(mtd, ONENAND_CMD_ERASE, addr, 0);
3680 ret = this->wait(mtd, FL_ERASING);
3681 if (ret) {
Mika Korhonenf369c7e2009-10-23 07:50:44 +02003682 printk(KERN_ERR "%s: Failed PI erase for Die %d\n",
3683 __func__, die);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003684 goto out;
3685 }
3686
3687 this->write_word(boundary, this->base + ONENAND_DATARAM);
3688 this->command(mtd, ONENAND_CMD_PROG, addr, 0);
3689 ret = this->wait(mtd, FL_WRITING);
3690 if (ret) {
Amul Kumar Saha297758f2009-10-02 16:59:11 +05303691 printk(KERN_ERR "%s: Failed PI write for Die %d\n",
3692 __func__, die);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003693 goto out;
3694 }
3695
3696 this->command(mtd, FLEXONENAND_CMD_PI_UPDATE, die, 0);
3697 ret = this->wait(mtd, FL_WRITING);
3698out:
3699 this->write_word(ONENAND_CMD_RESET, this->base + ONENAND_REG_COMMAND);
3700 this->wait(mtd, FL_RESETING);
3701 if (!ret)
3702 /* Recalculate device size on boundary change*/
3703 flexonenand_get_size(mtd);
3704
3705 return ret;
3706}
3707
3708/**
Kyungmin Parkad0d3632010-05-28 11:03:11 +09003709 * onenand_chip_probe - [OneNAND Interface] The generic chip probe
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003710 * @param mtd MTD device structure
3711 *
3712 * OneNAND detection method:
Michael Opdenacker59c51592007-05-09 08:57:56 +02003713 * Compare the values from command with ones from register
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003714 */
Kyungmin Parkad0d3632010-05-28 11:03:11 +09003715static int onenand_chip_probe(struct mtd_info *mtd)
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003716{
3717 struct onenand_chip *this = mtd->priv;
Kyungmin Parkad0d3632010-05-28 11:03:11 +09003718 int bram_maf_id, bram_dev_id, maf_id, dev_id;
Kyungmin Park47e777e2006-09-25 23:53:28 +00003719 int syscfg;
3720
3721 /* Save system configuration 1 */
3722 syscfg = this->read_word(this->base + ONENAND_REG_SYS_CFG1);
3723 /* Clear Sync. Burst Read mode to read BootRAM */
Adrian Hunteree8f3762009-05-05 11:04:19 +03003724 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 +01003725
3726 /* Send the command for reading device ID from BootRAM */
3727 this->write_word(ONENAND_CMD_READID, this->base + ONENAND_BOOTRAM);
3728
3729 /* Read manufacturer and device IDs from BootRAM */
3730 bram_maf_id = this->read_word(this->base + ONENAND_BOOTRAM + 0x0);
3731 bram_dev_id = this->read_word(this->base + ONENAND_BOOTRAM + 0x2);
3732
Kyungmin Park47e777e2006-09-25 23:53:28 +00003733 /* Reset OneNAND to read default register values */
3734 this->write_word(ONENAND_CMD_RESET, this->base + ONENAND_BOOTRAM);
3735 /* Wait reset */
3736 this->wait(mtd, FL_RESETING);
3737
3738 /* Restore system configuration 1 */
3739 this->write_word(syscfg, this->base + ONENAND_REG_SYS_CFG1);
3740
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003741 /* Check manufacturer ID */
3742 if (onenand_check_maf(bram_maf_id))
3743 return -ENXIO;
3744
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003745 /* Read manufacturer and device IDs from Register */
3746 maf_id = this->read_word(this->base + ONENAND_REG_MANUFACTURER_ID);
3747 dev_id = this->read_word(this->base + ONENAND_REG_DEVICE_ID);
3748
3749 /* Check OneNAND device */
3750 if (maf_id != bram_maf_id || dev_id != bram_dev_id)
3751 return -ENXIO;
3752
Kyungmin Parkad0d3632010-05-28 11:03:11 +09003753 return 0;
3754}
3755
3756/**
3757 * onenand_probe - [OneNAND Interface] Probe the OneNAND device
3758 * @param mtd MTD device structure
3759 */
3760static int onenand_probe(struct mtd_info *mtd)
3761{
3762 struct onenand_chip *this = mtd->priv;
Brian Norris6b7368c2013-08-27 18:01:19 -07003763 int dev_id, ver_id;
Kyungmin Parkad0d3632010-05-28 11:03:11 +09003764 int density;
3765 int ret;
3766
3767 ret = this->chip_probe(mtd);
3768 if (ret)
3769 return ret;
3770
Brian Norris6b7368c2013-08-27 18:01:19 -07003771 /* Device and version IDs from Register */
Kyungmin Parkad0d3632010-05-28 11:03:11 +09003772 dev_id = this->read_word(this->base + ONENAND_REG_DEVICE_ID);
3773 ver_id = this->read_word(this->base + ONENAND_REG_VERSION_ID);
3774 this->technology = this->read_word(this->base + ONENAND_REG_TECHNOLOGY);
3775
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003776 /* Flash device information */
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003777 onenand_print_device_info(dev_id, ver_id);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003778 this->device_id = dev_id;
Kyungmin Park28b79ff2006-09-26 09:45:28 +00003779 this->version_id = ver_id;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003780
Kyungmin Parkc37cb562010-04-28 17:46:48 +02003781 /* Check OneNAND features */
3782 onenand_check_features(mtd);
3783
Kyungmin Parke71f04f2007-12-11 11:23:45 +09003784 density = onenand_get_density(dev_id);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003785 if (FLEXONENAND(this)) {
3786 this->dies = ONENAND_IS_DDP(this) ? 2 : 1;
3787 /* Maximum possible erase regions */
3788 mtd->numeraseregions = this->dies << 1;
3789 mtd->eraseregions = kzalloc(sizeof(struct mtd_erase_region_info)
3790 * (this->dies << 1), GFP_KERNEL);
3791 if (!mtd->eraseregions)
3792 return -ENOMEM;
3793 }
3794
3795 /*
3796 * For Flex-OneNAND, chipsize represents maximum possible device size.
3797 * mtd->size represents the actual device size.
3798 */
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003799 this->chipsize = (16 << density) << 20;
3800
3801 /* OneNAND page size & block size */
3802 /* The data buffer size is equal to page size */
Joern Engel28318772006-05-22 23:18:05 +02003803 mtd->writesize = this->read_word(this->base + ONENAND_REG_DATA_BUFFER_SIZE);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003804 /* We use the full BufferRAM */
Kyungmin Park8a8f6322010-12-02 09:24:16 +09003805 if (ONENAND_IS_4KB_PAGE(this))
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003806 mtd->writesize <<= 1;
3807
Joern Engel28318772006-05-22 23:18:05 +02003808 mtd->oobsize = mtd->writesize >> 5;
Kyungmin Park9bfbc9b2007-01-31 14:25:21 +09003809 /* Pages per a block are always 64 in OneNAND */
Joern Engel28318772006-05-22 23:18:05 +02003810 mtd->erasesize = mtd->writesize << 6;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003811 /*
3812 * Flex-OneNAND SLC area has 64 pages per block.
3813 * Flex-OneNAND MLC area has 128 pages per block.
3814 * Expose MLC erase size to find erase_shift and page_mask.
3815 */
3816 if (FLEXONENAND(this))
3817 mtd->erasesize <<= 1;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003818
3819 this->erase_shift = ffs(mtd->erasesize) - 1;
Joern Engel28318772006-05-22 23:18:05 +02003820 this->page_shift = ffs(mtd->writesize) - 1;
Kyungmin Park9bfbc9b2007-01-31 14:25:21 +09003821 this->page_mask = (1 << (this->erase_shift - this->page_shift)) - 1;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003822 /* Set density mask. it is used for DDP */
3823 if (ONENAND_IS_DDP(this))
3824 this->density_mask = this->chipsize >> (this->erase_shift + 1);
Kyungmin Parkee9745f2007-06-30 13:57:49 +09003825 /* It's real page size */
3826 this->writesize = mtd->writesize;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003827
Mika Korhonen492e1502009-06-09 21:52:35 +03003828 /* REVISIT: Multichip handling */
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003829
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003830 if (FLEXONENAND(this))
3831 flexonenand_get_size(mtd);
3832 else
3833 mtd->size = this->chipsize;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003834
Kyungmin Parkee9745f2007-06-30 13:57:49 +09003835 /*
3836 * We emulate the 4KiB page and 256KiB erase block size
3837 * But oobsize is still 64 bytes.
3838 * It is only valid if you turn on 2X program support,
3839 * Otherwise it will be ignored by compiler.
3840 */
3841 if (ONENAND_IS_2PLANE(this)) {
3842 mtd->writesize <<= 1;
3843 mtd->erasesize <<= 1;
3844 }
3845
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003846 return 0;
3847}
3848
Kyungmin Parka41371e2005-09-29 03:55:31 +01003849/**
3850 * onenand_suspend - [MTD Interface] Suspend the OneNAND flash
3851 * @param mtd MTD device structure
3852 */
3853static int onenand_suspend(struct mtd_info *mtd)
3854{
3855 return onenand_get_device(mtd, FL_PM_SUSPENDED);
3856}
3857
3858/**
3859 * onenand_resume - [MTD Interface] Resume the OneNAND flash
3860 * @param mtd MTD device structure
3861 */
3862static void onenand_resume(struct mtd_info *mtd)
3863{
3864 struct onenand_chip *this = mtd->priv;
3865
3866 if (this->state == FL_PM_SUSPENDED)
3867 onenand_release_device(mtd);
3868 else
Amul Kumar Saha297758f2009-10-02 16:59:11 +05303869 printk(KERN_ERR "%s: resume() called for the chip which is not "
3870 "in suspended state\n", __func__);
Kyungmin Parka41371e2005-09-29 03:55:31 +01003871}
3872
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003873/**
3874 * onenand_scan - [OneNAND Interface] Scan for the OneNAND device
3875 * @param mtd MTD device structure
3876 * @param maxchips Number of chips to scan for
3877 *
3878 * This fills out all the not initialized function pointers
3879 * with the defaults.
3880 * The flash ID is read and the mtd/chip structures are
3881 * filled with the appropriate values.
3882 */
3883int onenand_scan(struct mtd_info *mtd, int maxchips)
3884{
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003885 int i, ret;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003886 struct onenand_chip *this = mtd->priv;
3887
3888 if (!this->read_word)
3889 this->read_word = onenand_readw;
3890 if (!this->write_word)
3891 this->write_word = onenand_writew;
3892
3893 if (!this->command)
3894 this->command = onenand_command;
3895 if (!this->wait)
Kyungmin Park2c221202006-11-16 11:23:48 +09003896 onenand_setup_wait(mtd);
Kyungmin Park31bb9992009-05-12 13:46:57 -07003897 if (!this->bbt_wait)
3898 this->bbt_wait = onenand_bbt_wait;
3899 if (!this->unlock_all)
3900 this->unlock_all = onenand_unlock_all;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003901
Kyungmin Parkad0d3632010-05-28 11:03:11 +09003902 if (!this->chip_probe)
3903 this->chip_probe = onenand_chip_probe;
3904
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003905 if (!this->read_bufferram)
3906 this->read_bufferram = onenand_read_bufferram;
3907 if (!this->write_bufferram)
3908 this->write_bufferram = onenand_write_bufferram;
3909
Kyungmin Parkcdc00132005-09-03 07:15:48 +01003910 if (!this->block_markbad)
3911 this->block_markbad = onenand_default_block_markbad;
3912 if (!this->scan_bbt)
3913 this->scan_bbt = onenand_default_bbt;
3914
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003915 if (onenand_probe(mtd))
3916 return -ENXIO;
3917
Kyungmin Park52b0eea2005-09-03 07:07:19 +01003918 /* Set Sync. Burst Read after probing */
3919 if (this->mmcontrol) {
3920 printk(KERN_INFO "OneNAND Sync. Burst Read support\n");
3921 this->read_bufferram = onenand_sync_read_bufferram;
3922 }
3923
Kyungmin Park532a37c2005-12-16 11:17:29 +09003924 /* Allocate buffers, if necessary */
3925 if (!this->page_buf) {
Kyungmin Park470bc842007-03-09 10:08:11 +09003926 this->page_buf = kzalloc(mtd->writesize, GFP_KERNEL);
Jingoo Hane4eec192014-02-06 15:15:38 +09003927 if (!this->page_buf)
Kyungmin Park532a37c2005-12-16 11:17:29 +09003928 return -ENOMEM;
Kyungmin Park4a8ce0b2010-04-28 17:46:46 +02003929#ifdef CONFIG_MTD_ONENAND_VERIFY_WRITE
3930 this->verify_buf = kzalloc(mtd->writesize, GFP_KERNEL);
3931 if (!this->verify_buf) {
3932 kfree(this->page_buf);
3933 return -ENOMEM;
3934 }
3935#endif
Kyungmin Park532a37c2005-12-16 11:17:29 +09003936 this->options |= ONENAND_PAGEBUF_ALLOC;
3937 }
Kyungmin Park470bc842007-03-09 10:08:11 +09003938 if (!this->oob_buf) {
3939 this->oob_buf = kzalloc(mtd->oobsize, GFP_KERNEL);
3940 if (!this->oob_buf) {
Kyungmin Park470bc842007-03-09 10:08:11 +09003941 if (this->options & ONENAND_PAGEBUF_ALLOC) {
3942 this->options &= ~ONENAND_PAGEBUF_ALLOC;
3943 kfree(this->page_buf);
3944 }
3945 return -ENOMEM;
3946 }
3947 this->options |= ONENAND_OOBBUF_ALLOC;
3948 }
Kyungmin Park532a37c2005-12-16 11:17:29 +09003949
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003950 this->state = FL_READY;
3951 init_waitqueue_head(&this->wq);
3952 spin_lock_init(&this->chip_lock);
3953
Kyungmin Park60d84f92006-12-22 16:21:54 +09003954 /*
3955 * Allow subpage writes up to oobsize.
3956 */
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003957 switch (mtd->oobsize) {
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003958 case 128:
Roman Tereshonkov99b17c02011-04-11 12:52:01 +03003959 if (FLEXONENAND(this)) {
3960 this->ecclayout = &flexonenand_oob_128;
3961 mtd->subpage_sft = 0;
3962 } else {
3963 this->ecclayout = &onenand_oob_128;
3964 mtd->subpage_sft = 2;
3965 }
Kyungmin Parke1c10242011-06-22 14:16:49 +09003966 if (ONENAND_IS_NOP_1(this))
3967 mtd->subpage_sft = 0;
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07003968 break;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003969 case 64:
Thomas Gleixner5bd34c02006-05-27 22:16:10 +02003970 this->ecclayout = &onenand_oob_64;
Kyungmin Park60d84f92006-12-22 16:21:54 +09003971 mtd->subpage_sft = 2;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003972 break;
3973
3974 case 32:
Thomas Gleixner5bd34c02006-05-27 22:16:10 +02003975 this->ecclayout = &onenand_oob_32;
Kyungmin Park60d84f92006-12-22 16:21:54 +09003976 mtd->subpage_sft = 1;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003977 break;
3978
3979 default:
Amul Kumar Saha297758f2009-10-02 16:59:11 +05303980 printk(KERN_WARNING "%s: No OOB scheme defined for oobsize %d\n",
3981 __func__, mtd->oobsize);
Kyungmin Park60d84f92006-12-22 16:21:54 +09003982 mtd->subpage_sft = 0;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003983 /* To prevent kernel oops */
Thomas Gleixner5bd34c02006-05-27 22:16:10 +02003984 this->ecclayout = &onenand_oob_32;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01003985 break;
3986 }
3987
Kyungmin Park60d84f92006-12-22 16:21:54 +09003988 this->subpagesize = mtd->writesize >> mtd->subpage_sft;
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02003989
3990 /*
3991 * The number of bytes available for a client to place data into
3992 * the out of band area
3993 */
Boris Brezillond30aae62016-02-03 20:12:31 +01003994 ret = mtd_ooblayout_count_freebytes(mtd);
3995 if (ret < 0)
3996 ret = 0;
3997
3998 mtd->oobavail = ret;
Adrian Huntera5e7c7b2007-01-31 17:19:28 +02003999
Thomas Gleixner5bd34c02006-05-27 22:16:10 +02004000 mtd->ecclayout = this->ecclayout;
Mike Dunn6a918ba2012-03-11 14:21:11 -07004001 mtd->ecc_strength = 1;
Thomas Gleixnerd5c5e782005-11-07 11:15:51 +00004002
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004003 /* Fill in remaining MTD driver data */
Rohit Hassan Sathyanarayanc7626802010-09-27 16:02:10 +05304004 mtd->type = ONENAND_IS_MLC(this) ? MTD_MLCNANDFLASH : MTD_NANDFLASH;
Joern Engel5fa43392006-05-22 23:18:29 +02004005 mtd->flags = MTD_CAP_NANDFLASH;
Artem Bityutskiy3c3c10b2012-01-30 14:58:32 +02004006 mtd->_erase = onenand_erase;
4007 mtd->_point = NULL;
4008 mtd->_unpoint = NULL;
4009 mtd->_read = onenand_read;
4010 mtd->_write = onenand_write;
4011 mtd->_read_oob = onenand_read_oob;
4012 mtd->_write_oob = onenand_write_oob;
4013 mtd->_panic_write = onenand_panic_write;
Kyungmin Park493c6462006-05-12 17:03:07 +03004014#ifdef CONFIG_MTD_ONENAND_OTP
Artem Bityutskiy3c3c10b2012-01-30 14:58:32 +02004015 mtd->_get_fact_prot_info = onenand_get_fact_prot_info;
4016 mtd->_read_fact_prot_reg = onenand_read_fact_prot_reg;
4017 mtd->_get_user_prot_info = onenand_get_user_prot_info;
4018 mtd->_read_user_prot_reg = onenand_read_user_prot_reg;
4019 mtd->_write_user_prot_reg = onenand_write_user_prot_reg;
4020 mtd->_lock_user_prot_reg = onenand_lock_user_prot_reg;
Kyungmin Park493c6462006-05-12 17:03:07 +03004021#endif
Artem Bityutskiy3c3c10b2012-01-30 14:58:32 +02004022 mtd->_sync = onenand_sync;
4023 mtd->_lock = onenand_lock;
4024 mtd->_unlock = onenand_unlock;
4025 mtd->_suspend = onenand_suspend;
4026 mtd->_resume = onenand_resume;
4027 mtd->_block_isbad = onenand_block_isbad;
4028 mtd->_block_markbad = onenand_block_markbad;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004029 mtd->owner = THIS_MODULE;
Anatolij Gustschin25dcd292010-12-16 23:42:17 +01004030 mtd->writebufsize = mtd->writesize;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004031
4032 /* Unlock whole block */
Roman Tereshonkovb3dcfd352011-02-17 13:44:41 +02004033 if (!(this->options & ONENAND_SKIP_INITIAL_UNLOCKING))
4034 this->unlock_all(mtd);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004035
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07004036 ret = this->scan_bbt(mtd);
4037 if ((!FLEXONENAND(this)) || ret)
4038 return ret;
4039
4040 /* Change Flex-OneNAND boundaries if required */
4041 for (i = 0; i < MAX_DIES; i++)
4042 flexonenand_set_boundary(mtd, i, flex_bdry[2 * i],
4043 flex_bdry[(2 * i) + 1]);
4044
4045 return 0;
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004046}
4047
4048/**
4049 * onenand_release - [OneNAND Interface] Free resources held by the OneNAND device
4050 * @param mtd MTD device structure
4051 */
4052void onenand_release(struct mtd_info *mtd)
4053{
Kyungmin Park532a37c2005-12-16 11:17:29 +09004054 struct onenand_chip *this = mtd->priv;
4055
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004056 /* Deregister partitions */
Jamie Iles711a6322011-05-23 10:22:56 +01004057 mtd_device_unregister(mtd);
Kyungmin Park532a37c2005-12-16 11:17:29 +09004058
4059 /* Free bad block table memory, if allocated */
Adrian Hunterf00b0042007-01-22 17:01:01 +09004060 if (this->bbm) {
4061 struct bbm_info *bbm = this->bbm;
4062 kfree(bbm->bbt);
Kyungmin Park532a37c2005-12-16 11:17:29 +09004063 kfree(this->bbm);
Adrian Hunterf00b0042007-01-22 17:01:01 +09004064 }
Kyungmin Park470bc842007-03-09 10:08:11 +09004065 /* Buffers allocated by onenand_scan */
Kyungmin Park4a8ce0b2010-04-28 17:46:46 +02004066 if (this->options & ONENAND_PAGEBUF_ALLOC) {
Kyungmin Park532a37c2005-12-16 11:17:29 +09004067 kfree(this->page_buf);
Kyungmin Park4a8ce0b2010-04-28 17:46:46 +02004068#ifdef CONFIG_MTD_ONENAND_VERIFY_WRITE
4069 kfree(this->verify_buf);
4070#endif
4071 }
Kyungmin Park470bc842007-03-09 10:08:11 +09004072 if (this->options & ONENAND_OOBBUF_ALLOC)
4073 kfree(this->oob_buf);
Rohit Hagargundgi5988af22009-05-12 13:46:57 -07004074 kfree(mtd->eraseregions);
Kyungmin Parkcd5f6342005-07-11 11:41:53 +01004075}
4076
4077EXPORT_SYMBOL_GPL(onenand_scan);
4078EXPORT_SYMBOL_GPL(onenand_release);
4079
4080MODULE_LICENSE("GPL");
4081MODULE_AUTHOR("Kyungmin Park <kyungmin.park@samsung.com>");
4082MODULE_DESCRIPTION("Generic OneNAND flash driver code");