xref: /rk3399_rockchip-uboot/fs/yaffs2/yaffs_mtdif.c (revision 0e8cc8bd92257da2e1df88cbc985e166e472ce61)
1*0e8cc8bdSWilliam Juul /*
2*0e8cc8bdSWilliam Juul  * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
3*0e8cc8bdSWilliam Juul  *
4*0e8cc8bdSWilliam Juul  * Copyright (C) 2002-2007 Aleph One Ltd.
5*0e8cc8bdSWilliam Juul  *   for Toby Churchill Ltd and Brightstar Engineering
6*0e8cc8bdSWilliam Juul  *
7*0e8cc8bdSWilliam Juul  * Created by Charles Manning <charles@aleph1.co.uk>
8*0e8cc8bdSWilliam Juul  *
9*0e8cc8bdSWilliam Juul  * This program is free software; you can redistribute it and/or modify
10*0e8cc8bdSWilliam Juul  * it under the terms of the GNU General Public License version 2 as
11*0e8cc8bdSWilliam Juul  * published by the Free Software Foundation.
12*0e8cc8bdSWilliam Juul  */
13*0e8cc8bdSWilliam Juul 
14*0e8cc8bdSWilliam Juul const char *yaffs_mtdif_c_version =
15*0e8cc8bdSWilliam Juul     "$Id: yaffs_mtdif.c,v 1.19 2007/02/14 01:09:06 wookey Exp $";
16*0e8cc8bdSWilliam Juul 
17*0e8cc8bdSWilliam Juul #include "yportenv.h"
18*0e8cc8bdSWilliam Juul 
19*0e8cc8bdSWilliam Juul 
20*0e8cc8bdSWilliam Juul #include "yaffs_mtdif.h"
21*0e8cc8bdSWilliam Juul 
22*0e8cc8bdSWilliam Juul #include "linux/mtd/mtd.h"
23*0e8cc8bdSWilliam Juul #include "linux/types.h"
24*0e8cc8bdSWilliam Juul #include "linux/time.h"
25*0e8cc8bdSWilliam Juul #include "linux/mtd/nand.h"
26*0e8cc8bdSWilliam Juul 
27*0e8cc8bdSWilliam Juul #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18))
28*0e8cc8bdSWilliam Juul static struct nand_oobinfo yaffs_oobinfo = {
29*0e8cc8bdSWilliam Juul 	.useecc = 1,
30*0e8cc8bdSWilliam Juul 	.eccbytes = 6,
31*0e8cc8bdSWilliam Juul 	.eccpos = {8, 9, 10, 13, 14, 15}
32*0e8cc8bdSWilliam Juul };
33*0e8cc8bdSWilliam Juul 
34*0e8cc8bdSWilliam Juul static struct nand_oobinfo yaffs_noeccinfo = {
35*0e8cc8bdSWilliam Juul 	.useecc = 0,
36*0e8cc8bdSWilliam Juul };
37*0e8cc8bdSWilliam Juul #endif
38*0e8cc8bdSWilliam Juul 
39*0e8cc8bdSWilliam Juul #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
40*0e8cc8bdSWilliam Juul static inline void translate_spare2oob(const yaffs_Spare *spare, __u8 *oob)
41*0e8cc8bdSWilliam Juul {
42*0e8cc8bdSWilliam Juul 	oob[0] = spare->tagByte0;
43*0e8cc8bdSWilliam Juul 	oob[1] = spare->tagByte1;
44*0e8cc8bdSWilliam Juul 	oob[2] = spare->tagByte2;
45*0e8cc8bdSWilliam Juul 	oob[3] = spare->tagByte3;
46*0e8cc8bdSWilliam Juul 	oob[4] = spare->tagByte4;
47*0e8cc8bdSWilliam Juul 	oob[5] = spare->tagByte5 & 0x3f;
48*0e8cc8bdSWilliam Juul 	oob[5] |= spare->blockStatus == 'Y' ? 0: 0x80;
49*0e8cc8bdSWilliam Juul 	oob[5] |= spare->pageStatus == 0 ? 0: 0x40;
50*0e8cc8bdSWilliam Juul 	oob[6] = spare->tagByte6;
51*0e8cc8bdSWilliam Juul 	oob[7] = spare->tagByte7;
52*0e8cc8bdSWilliam Juul }
53*0e8cc8bdSWilliam Juul 
54*0e8cc8bdSWilliam Juul static inline void translate_oob2spare(yaffs_Spare *spare, __u8 *oob)
55*0e8cc8bdSWilliam Juul {
56*0e8cc8bdSWilliam Juul 	struct yaffs_NANDSpare *nspare = (struct yaffs_NANDSpare *)spare;
57*0e8cc8bdSWilliam Juul 	spare->tagByte0 = oob[0];
58*0e8cc8bdSWilliam Juul 	spare->tagByte1 = oob[1];
59*0e8cc8bdSWilliam Juul 	spare->tagByte2 = oob[2];
60*0e8cc8bdSWilliam Juul 	spare->tagByte3 = oob[3];
61*0e8cc8bdSWilliam Juul 	spare->tagByte4 = oob[4];
62*0e8cc8bdSWilliam Juul 	spare->tagByte5 = oob[5] == 0xff ? 0xff : oob[5] & 0x3f;
63*0e8cc8bdSWilliam Juul 	spare->blockStatus = oob[5] & 0x80 ? 0xff : 'Y';
64*0e8cc8bdSWilliam Juul 	spare->pageStatus = oob[5] & 0x40 ? 0xff : 0;
65*0e8cc8bdSWilliam Juul 	spare->ecc1[0] = spare->ecc1[1] = spare->ecc1[2] = 0xff;
66*0e8cc8bdSWilliam Juul 	spare->tagByte6 = oob[6];
67*0e8cc8bdSWilliam Juul 	spare->tagByte7 = oob[7];
68*0e8cc8bdSWilliam Juul 	spare->ecc2[0] = spare->ecc2[1] = spare->ecc2[2] = 0xff;
69*0e8cc8bdSWilliam Juul 
70*0e8cc8bdSWilliam Juul 	nspare->eccres1 = nspare->eccres2 = 0; /* FIXME */
71*0e8cc8bdSWilliam Juul }
72*0e8cc8bdSWilliam Juul #endif
73*0e8cc8bdSWilliam Juul 
74*0e8cc8bdSWilliam Juul int nandmtd_WriteChunkToNAND(yaffs_Device * dev, int chunkInNAND,
75*0e8cc8bdSWilliam Juul 			     const __u8 * data, const yaffs_Spare * spare)
76*0e8cc8bdSWilliam Juul {
77*0e8cc8bdSWilliam Juul 	struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
78*0e8cc8bdSWilliam Juul #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
79*0e8cc8bdSWilliam Juul 	struct mtd_oob_ops ops;
80*0e8cc8bdSWilliam Juul #endif
81*0e8cc8bdSWilliam Juul 	size_t dummy;
82*0e8cc8bdSWilliam Juul 	int retval = 0;
83*0e8cc8bdSWilliam Juul 
84*0e8cc8bdSWilliam Juul 	loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;
85*0e8cc8bdSWilliam Juul #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
86*0e8cc8bdSWilliam Juul 	__u8 spareAsBytes[8]; /* OOB */
87*0e8cc8bdSWilliam Juul 
88*0e8cc8bdSWilliam Juul 	if (data && !spare)
89*0e8cc8bdSWilliam Juul 		retval = mtd->write(mtd, addr, dev->nDataBytesPerChunk,
90*0e8cc8bdSWilliam Juul 				&dummy, data);
91*0e8cc8bdSWilliam Juul 	else if (spare) {
92*0e8cc8bdSWilliam Juul 		if (dev->useNANDECC) {
93*0e8cc8bdSWilliam Juul 			translate_spare2oob(spare, spareAsBytes);
94*0e8cc8bdSWilliam Juul 			ops.mode = MTD_OOB_AUTO;
95*0e8cc8bdSWilliam Juul 			ops.ooblen = 8; /* temp hack */
96*0e8cc8bdSWilliam Juul 		} else {
97*0e8cc8bdSWilliam Juul 			ops.mode = MTD_OOB_RAW;
98*0e8cc8bdSWilliam Juul 			ops.ooblen = YAFFS_BYTES_PER_SPARE;
99*0e8cc8bdSWilliam Juul 		}
100*0e8cc8bdSWilliam Juul 		ops.len = data ? dev->nDataBytesPerChunk : ops.ooblen;
101*0e8cc8bdSWilliam Juul 		ops.datbuf = (u8 *)data;
102*0e8cc8bdSWilliam Juul 		ops.ooboffs = 0;
103*0e8cc8bdSWilliam Juul 		ops.oobbuf = spareAsBytes;
104*0e8cc8bdSWilliam Juul 		retval = mtd->write_oob(mtd, addr, &ops);
105*0e8cc8bdSWilliam Juul 	}
106*0e8cc8bdSWilliam Juul #else
107*0e8cc8bdSWilliam Juul 	__u8 *spareAsBytes = (__u8 *) spare;
108*0e8cc8bdSWilliam Juul 
109*0e8cc8bdSWilliam Juul 	if (data && spare) {
110*0e8cc8bdSWilliam Juul 		if (dev->useNANDECC)
111*0e8cc8bdSWilliam Juul 			retval =
112*0e8cc8bdSWilliam Juul 			    mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
113*0e8cc8bdSWilliam Juul 					   &dummy, data, spareAsBytes,
114*0e8cc8bdSWilliam Juul 					   &yaffs_oobinfo);
115*0e8cc8bdSWilliam Juul 		else
116*0e8cc8bdSWilliam Juul 			retval =
117*0e8cc8bdSWilliam Juul 			    mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
118*0e8cc8bdSWilliam Juul 					   &dummy, data, spareAsBytes,
119*0e8cc8bdSWilliam Juul 					   &yaffs_noeccinfo);
120*0e8cc8bdSWilliam Juul 	} else {
121*0e8cc8bdSWilliam Juul 		if (data)
122*0e8cc8bdSWilliam Juul 			retval =
123*0e8cc8bdSWilliam Juul 			    mtd->write(mtd, addr, dev->nDataBytesPerChunk, &dummy,
124*0e8cc8bdSWilliam Juul 				       data);
125*0e8cc8bdSWilliam Juul 		if (spare)
126*0e8cc8bdSWilliam Juul 			retval =
127*0e8cc8bdSWilliam Juul 			    mtd->write_oob(mtd, addr, YAFFS_BYTES_PER_SPARE,
128*0e8cc8bdSWilliam Juul 					   &dummy, spareAsBytes);
129*0e8cc8bdSWilliam Juul 	}
130*0e8cc8bdSWilliam Juul #endif
131*0e8cc8bdSWilliam Juul 
132*0e8cc8bdSWilliam Juul 	if (retval == 0)
133*0e8cc8bdSWilliam Juul 		return YAFFS_OK;
134*0e8cc8bdSWilliam Juul 	else
135*0e8cc8bdSWilliam Juul 		return YAFFS_FAIL;
136*0e8cc8bdSWilliam Juul }
137*0e8cc8bdSWilliam Juul 
138*0e8cc8bdSWilliam Juul int nandmtd_ReadChunkFromNAND(yaffs_Device * dev, int chunkInNAND, __u8 * data,
139*0e8cc8bdSWilliam Juul 			      yaffs_Spare * spare)
140*0e8cc8bdSWilliam Juul {
141*0e8cc8bdSWilliam Juul 	struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
142*0e8cc8bdSWilliam Juul #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
143*0e8cc8bdSWilliam Juul 	struct mtd_oob_ops ops;
144*0e8cc8bdSWilliam Juul #endif
145*0e8cc8bdSWilliam Juul 	size_t dummy;
146*0e8cc8bdSWilliam Juul 	int retval = 0;
147*0e8cc8bdSWilliam Juul 
148*0e8cc8bdSWilliam Juul 	loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;
149*0e8cc8bdSWilliam Juul #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
150*0e8cc8bdSWilliam Juul 	__u8 spareAsBytes[8]; /* OOB */
151*0e8cc8bdSWilliam Juul 
152*0e8cc8bdSWilliam Juul 	if (data && !spare)
153*0e8cc8bdSWilliam Juul 		retval = mtd->read(mtd, addr, dev->nDataBytesPerChunk,
154*0e8cc8bdSWilliam Juul 				&dummy, data);
155*0e8cc8bdSWilliam Juul 	else if (spare) {
156*0e8cc8bdSWilliam Juul 		if (dev->useNANDECC) {
157*0e8cc8bdSWilliam Juul 			ops.mode = MTD_OOB_AUTO;
158*0e8cc8bdSWilliam Juul 			ops.ooblen = 8; /* temp hack */
159*0e8cc8bdSWilliam Juul 		} else {
160*0e8cc8bdSWilliam Juul 			ops.mode = MTD_OOB_RAW;
161*0e8cc8bdSWilliam Juul 			ops.ooblen = YAFFS_BYTES_PER_SPARE;
162*0e8cc8bdSWilliam Juul 		}
163*0e8cc8bdSWilliam Juul 		ops.len = data ? dev->nDataBytesPerChunk : ops.ooblen;
164*0e8cc8bdSWilliam Juul 		ops.datbuf = data;
165*0e8cc8bdSWilliam Juul 		ops.ooboffs = 0;
166*0e8cc8bdSWilliam Juul 		ops.oobbuf = spareAsBytes;
167*0e8cc8bdSWilliam Juul 		retval = mtd->read_oob(mtd, addr, &ops);
168*0e8cc8bdSWilliam Juul 		if (dev->useNANDECC)
169*0e8cc8bdSWilliam Juul 			translate_oob2spare(spare, spareAsBytes);
170*0e8cc8bdSWilliam Juul 	}
171*0e8cc8bdSWilliam Juul #else
172*0e8cc8bdSWilliam Juul 	__u8 *spareAsBytes = (__u8 *) spare;
173*0e8cc8bdSWilliam Juul 
174*0e8cc8bdSWilliam Juul 	if (data && spare) {
175*0e8cc8bdSWilliam Juul 		if (dev->useNANDECC) {
176*0e8cc8bdSWilliam Juul 			/* Careful, this call adds 2 ints */
177*0e8cc8bdSWilliam Juul 			/* to the end of the spare data.  Calling function */
178*0e8cc8bdSWilliam Juul 			/* should allocate enough memory for spare, */
179*0e8cc8bdSWilliam Juul 			/* i.e. [YAFFS_BYTES_PER_SPARE+2*sizeof(int)]. */
180*0e8cc8bdSWilliam Juul 			retval =
181*0e8cc8bdSWilliam Juul 			    mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
182*0e8cc8bdSWilliam Juul 					  &dummy, data, spareAsBytes,
183*0e8cc8bdSWilliam Juul 					  &yaffs_oobinfo);
184*0e8cc8bdSWilliam Juul 		} else {
185*0e8cc8bdSWilliam Juul 			retval =
186*0e8cc8bdSWilliam Juul 			    mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
187*0e8cc8bdSWilliam Juul 					  &dummy, data, spareAsBytes,
188*0e8cc8bdSWilliam Juul 					  &yaffs_noeccinfo);
189*0e8cc8bdSWilliam Juul 		}
190*0e8cc8bdSWilliam Juul 	} else {
191*0e8cc8bdSWilliam Juul 		if (data)
192*0e8cc8bdSWilliam Juul 			retval =
193*0e8cc8bdSWilliam Juul 			    mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy,
194*0e8cc8bdSWilliam Juul 				      data);
195*0e8cc8bdSWilliam Juul 		if (spare)
196*0e8cc8bdSWilliam Juul 			retval =
197*0e8cc8bdSWilliam Juul 			    mtd->read_oob(mtd, addr, YAFFS_BYTES_PER_SPARE,
198*0e8cc8bdSWilliam Juul 					  &dummy, spareAsBytes);
199*0e8cc8bdSWilliam Juul 	}
200*0e8cc8bdSWilliam Juul #endif
201*0e8cc8bdSWilliam Juul 
202*0e8cc8bdSWilliam Juul 	if (retval == 0)
203*0e8cc8bdSWilliam Juul 		return YAFFS_OK;
204*0e8cc8bdSWilliam Juul 	else
205*0e8cc8bdSWilliam Juul 		return YAFFS_FAIL;
206*0e8cc8bdSWilliam Juul }
207*0e8cc8bdSWilliam Juul 
208*0e8cc8bdSWilliam Juul int nandmtd_EraseBlockInNAND(yaffs_Device * dev, int blockNumber)
209*0e8cc8bdSWilliam Juul {
210*0e8cc8bdSWilliam Juul 	struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
211*0e8cc8bdSWilliam Juul 	__u32 addr =
212*0e8cc8bdSWilliam Juul 	    ((loff_t) blockNumber) * dev->nDataBytesPerChunk
213*0e8cc8bdSWilliam Juul 		* dev->nChunksPerBlock;
214*0e8cc8bdSWilliam Juul 	struct erase_info ei;
215*0e8cc8bdSWilliam Juul 	int retval = 0;
216*0e8cc8bdSWilliam Juul 
217*0e8cc8bdSWilliam Juul 	ei.mtd = mtd;
218*0e8cc8bdSWilliam Juul 	ei.addr = addr;
219*0e8cc8bdSWilliam Juul 	ei.len = dev->nDataBytesPerChunk * dev->nChunksPerBlock;
220*0e8cc8bdSWilliam Juul 	ei.time = 1000;
221*0e8cc8bdSWilliam Juul 	ei.retries = 2;
222*0e8cc8bdSWilliam Juul 	ei.callback = NULL;
223*0e8cc8bdSWilliam Juul 	ei.priv = (u_long) dev;
224*0e8cc8bdSWilliam Juul 
225*0e8cc8bdSWilliam Juul 	/* Todo finish off the ei if required */
226*0e8cc8bdSWilliam Juul 
227*0e8cc8bdSWilliam Juul 	sema_init(&dev->sem, 0);
228*0e8cc8bdSWilliam Juul 
229*0e8cc8bdSWilliam Juul 	retval = mtd->erase(mtd, &ei);
230*0e8cc8bdSWilliam Juul 
231*0e8cc8bdSWilliam Juul 	if (retval == 0)
232*0e8cc8bdSWilliam Juul 		return YAFFS_OK;
233*0e8cc8bdSWilliam Juul 	else
234*0e8cc8bdSWilliam Juul 		return YAFFS_FAIL;
235*0e8cc8bdSWilliam Juul }
236*0e8cc8bdSWilliam Juul 
237*0e8cc8bdSWilliam Juul int nandmtd_InitialiseNAND(yaffs_Device * dev)
238*0e8cc8bdSWilliam Juul {
239*0e8cc8bdSWilliam Juul 	return YAFFS_OK;
240*0e8cc8bdSWilliam Juul }
241*0e8cc8bdSWilliam Juul 
242