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