Mercurial > yaffs-ecoscentric-gpl
annotate packages/fs/yaffs/current/src/direct/yaffs_norif1.c @ 425:dea4d7d250ad ecos
Move sources into packages/fs/yaffs/current/src/
| author | Ross Younger <wry@ecoscentric.com> |
|---|---|
| date | Fri, 14 May 2010 16:03:09 +0100 |
| parents | direct/yaffs_norif1.c@b5309c9b6d7f |
| children |
| rev | line source |
|---|---|
| 224 | 1 /* |
| 2 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. | |
| 3 * | |
|
409
b5309c9b6d7f
yaffs Some cleanups.
Charles Manning <cdhmanning@gmail.com>
parents:
356
diff
changeset
|
4 * Copyright (C) 2002-2010 Aleph One Ltd. |
| 224 | 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 /* | |
| 15 * This is an interface module for handling NOR in yaffs1 mode. | |
| 16 */ | |
| 17 | |
| 18 /* First set up for M18 with 1k chunks and 16-byte spares. | |
| 19 * | |
| 20 * NB We're using the oddball M18 modes of operation here | |
| 21 * The chip is 64MB based at 0x0000, but YAFFS only going to use the top half | |
| 22 * ie. YAFFS will be from 32MB to 64MB. | |
| 23 * | |
| 24 * The M18 has two ways of writing data. Every Programming Region (1kbytes) | |
| 25 * can be programmed in two modes: | |
| 26 * * Object Mode 1024 bytes of write once data. | |
| 27 * * Control Mode: 512bytes of bit-writeable data. | |
| 28 * This is arranged as 32 * (16 bytes of bit-writable followed by 16 bytes of "dont touch") | |
| 29 * | |
| 30 * The block size is 256kB, making 128 blocks in the 32MB YAFFS area. | |
| 31 * Each block comprises: | |
| 32 * Offset 0k: 248 x 1k data pages | |
| 33 * Offset 248k: 248 x 32-byte spare areas implemented as 16 bytes of spare followed by 16 bytes untouched) | |
| 34 * Offset 248k + (248 * 32): Format marker | |
| 35 * | |
| 36 */ | |
| 37 | |
|
356
7ee0cc4ba753
Rationalise context and parameter handling
charles <charles>
parents:
342
diff
changeset
|
38 const char *yaffs_norif1_c_version = "$Id: yaffs_norif1.c,v 1.6 2010-02-18 01:18:04 charles Exp $"; |
| 224 | 39 |
| 40 #include "yaffs_norif1.h" | |
| 41 | |
| 42 #include "yportenv.h" | |
| 342 | 43 #include "yaffs_trace.h" |
| 224 | 44 |
| 45 #include "yaffs_flashif.h" | |
| 46 #include "yaffs_guts.h" | |
| 47 | |
| 48 #include "devextras.h" | |
| 49 | |
| 50 #define SPARE_BYTES_PER_CHUNK 16 | |
| 51 #define M18_SKIP 16 | |
| 52 #define PROG_REGION_SIZE 1024 | |
| 53 #define BLOCK_SIZE_IN_BYTES (256*1024) | |
| 54 #define CHUNKS_PER_BLOCK 248 | |
| 55 #define SPARE_AREA_OFFSET (CHUNKS_PER_BLOCK * PROG_REGION_SIZE) | |
| 56 | |
| 57 #define FORMAT_OFFSET (SPARE_AREA_OFFSET + CHUNKS_PER_BLOCK * (SPARE_BYTES_PER_CHUNK + M18_SKIP)) | |
| 58 | |
| 59 #define FORMAT_VALUE 0x1234 | |
| 60 | |
| 61 #define DATA_BYTES_PER_CHUNK 1024 | |
|
226
37c7c7aaf779
Reduce size for nor simulation testing to try force errors
charles <charles>
parents:
224
diff
changeset
|
62 #define BLOCKS_IN_DEVICE (8*1024/256) |
| 224 | 63 |
| 64 | |
| 65 #define YNOR_PREMARKER (0xF6) | |
| 66 #define YNOR_POSTMARKER (0xF0) | |
| 67 | |
| 68 | |
| 69 #if 1 | |
| 70 | |
| 71 /* Compile this for a simulation */ | |
| 72 #include "ynorsim.h" | |
| 73 #define ynorif1_FlashInit() ynorsim_Initialise() | |
| 74 #define ynorif1_FlashDeinit() ynorsim_Shutdown() | |
| 75 #define ynorif1_FlashWrite32(addr,buf,nwords) ynorsim_Write32(addr,buf,nwords) | |
| 76 #define ynorif1_FlashRead32(addr,buf,nwords) ynorsim_Read32(addr,buf,nwords) | |
| 77 #define ynorif1_FlashEraseBlock(addr) ynorsim_EraseBlock(addr) | |
| 78 #define DEVICE_BASE ynorsim_GetBase() | |
| 79 #else | |
| 80 | |
| 81 /* Compile this for running on blob, hacked for yaffs access */ | |
| 82 #include "../blob/yflashrw.h" | |
| 83 #define ynorif1_FlashInit() do{} while(0) | |
| 84 #define ynorif1_FlashDeinit() do {} while(0) | |
| 85 #define ynorif1_FlashWrite32(addr,buf,nwords) Y_FlashWrite(addr,buf,nwords) | |
| 86 #define ynorif1_FlashRead32(addr,buf,nwords) Y_FlashRead(addr,buf,nwords) | |
| 87 #define ynorif1_FlashEraseBlock(addr) Y_FlashErase(addr,BLOCK_SIZE_IN_BYTES) | |
| 88 #define DEVICE_BASE (32 * 1024 * 1024) | |
| 89 #endif | |
| 90 | |
| 91 __u32 *Block2Addr(yaffs_Device *dev, int blockNumber) | |
| 92 { | |
| 93 __u32 addr; | |
| 94 | |
| 95 addr = (__u32) DEVICE_BASE; | |
| 96 addr += blockNumber * BLOCK_SIZE_IN_BYTES; | |
| 97 | |
| 98 return (__u32 *) addr; | |
| 99 } | |
| 100 | |
| 101 __u32 *Block2FormatAddr(yaffs_Device *dev,int blockNumber) | |
| 102 { | |
| 103 __u32 addr; | |
| 104 | |
| 105 addr = (__u32) Block2Addr(dev,blockNumber); | |
| 106 addr += FORMAT_OFFSET; | |
| 107 | |
| 108 return (__u32 *)addr; | |
| 109 } | |
| 110 __u32 *Chunk2DataAddr(yaffs_Device *dev,int chunkId) | |
| 111 { | |
| 112 unsigned block; | |
| 113 unsigned chunkInBlock; | |
| 114 __u32 addr; | |
| 115 | |
|
356
7ee0cc4ba753
Rationalise context and parameter handling
charles <charles>
parents:
342
diff
changeset
|
116 block = chunkId/dev->param.nChunksPerBlock; |
|
7ee0cc4ba753
Rationalise context and parameter handling
charles <charles>
parents:
342
diff
changeset
|
117 chunkInBlock = chunkId % dev->param.nChunksPerBlock; |
| 224 | 118 |
| 119 addr = (__u32) Block2Addr(dev,block); | |
| 120 addr += chunkInBlock * DATA_BYTES_PER_CHUNK; | |
| 121 | |
| 122 return (__u32 *)addr; | |
| 123 } | |
| 124 | |
| 125 __u32 *Chunk2SpareAddr(yaffs_Device *dev,int chunkId) | |
| 126 { | |
| 127 unsigned block; | |
| 128 unsigned chunkInBlock; | |
| 129 __u32 addr; | |
| 130 | |
|
356
7ee0cc4ba753
Rationalise context and parameter handling
charles <charles>
parents:
342
diff
changeset
|
131 block = chunkId/dev->param.nChunksPerBlock; |
|
7ee0cc4ba753
Rationalise context and parameter handling
charles <charles>
parents:
342
diff
changeset
|
132 chunkInBlock = chunkId % dev->param.nChunksPerBlock; |
| 224 | 133 |
| 134 addr = (__u32) Block2Addr(dev,block); | |
| 135 addr += SPARE_AREA_OFFSET; | |
| 136 addr += chunkInBlock * (SPARE_BYTES_PER_CHUNK + M18_SKIP); | |
| 137 return (__u32 *)addr; | |
| 138 } | |
| 139 | |
| 140 | |
| 141 void ynorif1_AndBytes(__u8*target, const __u8 *src, int nbytes) | |
| 142 { | |
| 143 while(nbytes > 0){ | |
| 144 *target &= *src; | |
| 145 target++; | |
| 146 src++; | |
| 147 nbytes--; | |
| 148 } | |
| 149 } | |
| 150 | |
| 151 int ynorif1_WriteChunkToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, const yaffs_Spare *spare) | |
| 152 { | |
| 153 __u32 *dataAddr = Chunk2DataAddr(dev,chunkInNAND); | |
| 154 __u32 *spareAddr = Chunk2SpareAddr(dev,chunkInNAND); | |
| 155 | |
| 156 yaffs_Spare tmpSpare; | |
| 157 | |
| 158 /* We should only be getting called for one of 3 reasons: | |
| 159 * Writing a chunk: data and spare will not be NULL | |
| 160 * Writing a deletion marker: data will be NULL, spare not NULL | |
| 161 * Writing a bad block marker: data will be NULL, spare not NULL | |
| 162 */ | |
| 163 | |
| 164 if(sizeof(yaffs_Spare) != 16) | |
| 165 YBUG(); | |
| 166 | |
| 167 if(data && spare) | |
| 168 { | |
| 169 if(spare->pageStatus != 0xff) | |
| 170 YBUG(); | |
| 171 /* Write a pre-marker */ | |
| 172 memset(&tmpSpare,0xff,sizeof(tmpSpare)); | |
| 173 tmpSpare.pageStatus = YNOR_PREMARKER; | |
| 174 ynorif1_FlashWrite32(spareAddr,(__u32 *)&tmpSpare,sizeof(yaffs_Spare)/4); | |
| 175 | |
| 176 /* Write the data */ | |
|
356
7ee0cc4ba753
Rationalise context and parameter handling
charles <charles>
parents:
342
diff
changeset
|
177 ynorif1_FlashWrite32(dataAddr,(__u32 *)data,dev->param.totalBytesPerChunk / 4); |
| 224 | 178 |
| 179 | |
| 180 memcpy(&tmpSpare,spare,sizeof(yaffs_Spare)); | |
| 181 | |
| 182 /* Write the real tags, but override the premarker*/ | |
| 183 tmpSpare.pageStatus = YNOR_PREMARKER; | |
| 184 ynorif1_FlashWrite32(spareAddr,(__u32 *)&tmpSpare,sizeof(yaffs_Spare)/4); | |
| 185 | |
| 186 /* Write a post-marker */ | |
| 187 tmpSpare.pageStatus = YNOR_POSTMARKER; | |
| 188 ynorif1_FlashWrite32(spareAddr,(__u32 *)&tmpSpare,sizeof(tmpSpare)/4); | |
| 189 | |
| 190 } else if(spare){ | |
| 191 /* This has to be a read-modify-write operation to handle NOR-ness */ | |
| 192 | |
| 193 ynorif1_FlashRead32(spareAddr,(__u32 *)&tmpSpare,16/ 4); | |
| 194 | |
| 195 ynorif1_AndBytes((__u8 *)&tmpSpare,(__u8 *)spare,sizeof(yaffs_Spare)); | |
| 196 | |
| 197 ynorif1_FlashWrite32(spareAddr,(__u32 *)&tmpSpare,16/ 4); | |
| 198 } | |
| 199 else { | |
| 200 YBUG(); | |
| 201 } | |
| 202 | |
| 203 | |
| 204 return YAFFS_OK; | |
| 205 | |
| 206 } | |
| 207 | |
| 208 int ynorif1_ReadChunkFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_Spare *spare) | |
| 209 { | |
| 210 | |
| 211 __u32 *dataAddr = Chunk2DataAddr(dev,chunkInNAND); | |
| 212 __u32 *spareAddr = Chunk2SpareAddr(dev,chunkInNAND); | |
| 213 | |
| 214 if(data) | |
| 215 { | |
|
356
7ee0cc4ba753
Rationalise context and parameter handling
charles <charles>
parents:
342
diff
changeset
|
216 ynorif1_FlashRead32(dataAddr,(__u32 *)data,dev->param.totalBytesPerChunk / 4); |
| 224 | 217 } |
| 218 | |
| 219 if(spare) | |
| 220 { | |
| 221 ynorif1_FlashRead32(spareAddr,(__u32 *)spare,16/ 4); | |
| 222 | |
|
228
16c5e095a48e
Extra page status checking to combat power loss causing only one bit to change
charles <charles>
parents:
226
diff
changeset
|
223 /* If the page status is YNOR_POSTMARKER then it was written properly |
| 224 | 224 * so change that to 0xFF so that the rest of yaffs is happy. |
| 225 */ | |
| 226 if(spare->pageStatus == YNOR_POSTMARKER) | |
| 227 spare->pageStatus = 0xFF; | |
|
228
16c5e095a48e
Extra page status checking to combat power loss causing only one bit to change
charles <charles>
parents:
226
diff
changeset
|
228 else if(spare->pageStatus != 0xff && |
| 239 | 229 (spare->pageStatus | YNOR_PREMARKER) != 0xff) |
|
228
16c5e095a48e
Extra page status checking to combat power loss causing only one bit to change
charles <charles>
parents:
226
diff
changeset
|
230 spare->pageStatus = YNOR_PREMARKER; |
| 224 | 231 } |
| 232 | |
| 233 | |
| 234 return YAFFS_OK; | |
| 235 | |
| 236 } | |
| 237 | |
| 238 static int ynorif1_FormatBlock(yaffs_Device *dev, int blockNumber) | |
| 239 { | |
| 240 __u32 *blockAddr = Block2Addr(dev,blockNumber); | |
| 241 __u32 *formatAddr = Block2FormatAddr(dev,blockNumber); | |
| 242 __u32 formatValue = FORMAT_VALUE; | |
| 243 | |
| 244 ynorif1_FlashEraseBlock(blockAddr); | |
| 245 ynorif1_FlashWrite32(formatAddr,&formatValue,1); | |
| 246 | |
| 247 return YAFFS_OK; | |
| 248 } | |
| 249 | |
| 250 static int ynorif1_UnformatBlock(yaffs_Device *dev, int blockNumber) | |
| 251 { | |
| 252 __u32 *formatAddr = Block2FormatAddr(dev,blockNumber); | |
| 253 __u32 formatValue = 0; | |
| 254 | |
| 255 ynorif1_FlashWrite32(formatAddr,&formatValue,1); | |
| 256 | |
| 257 return YAFFS_OK; | |
| 258 } | |
| 259 | |
| 260 static int ynorif1_IsBlockFormatted(yaffs_Device *dev, int blockNumber) | |
| 261 { | |
| 262 __u32 *formatAddr = Block2FormatAddr(dev,blockNumber); | |
| 263 __u32 formatValue; | |
| 264 | |
| 265 | |
| 266 ynorif1_FlashRead32(formatAddr,&formatValue,1); | |
| 267 | |
| 268 return (formatValue == FORMAT_VALUE); | |
| 269 } | |
| 270 | |
| 271 int ynorif1_EraseBlockInNAND(yaffs_Device *dev, int blockNumber) | |
| 272 { | |
| 273 | |
| 274 if(blockNumber < 0 || blockNumber >= BLOCKS_IN_DEVICE) | |
| 275 { | |
| 276 T(YAFFS_TRACE_ALWAYS,("Attempt to erase non-existant block %d\n",blockNumber)); | |
| 277 return YAFFS_FAIL; | |
| 278 } | |
| 279 else | |
| 280 { | |
| 281 ynorif1_UnformatBlock(dev,blockNumber); | |
| 282 ynorif1_FormatBlock(dev,blockNumber); | |
| 283 return YAFFS_OK; | |
| 284 } | |
| 285 | |
| 286 } | |
| 287 | |
| 288 int ynorif1_InitialiseNAND(yaffs_Device *dev) | |
| 289 { | |
| 290 int i; | |
| 291 | |
| 292 ynorif1_FlashInit(); | |
| 293 /* Go through the blocks formatting them if they are not formatted */ | |
|
356
7ee0cc4ba753
Rationalise context and parameter handling
charles <charles>
parents:
342
diff
changeset
|
294 for(i = dev->param.startBlock; i <= dev->param.endBlock; i++){ |
| 224 | 295 if(!ynorif1_IsBlockFormatted(dev,i)){ |
| 296 ynorif1_FormatBlock(dev,i); | |
| 297 } | |
| 298 } | |
| 299 return YAFFS_OK; | |
| 300 } | |
| 301 | |
| 302 int ynorif1_DeinitialiseNAND(yaffs_Device *dev) | |
| 303 { | |
| 304 | |
| 305 ynorif1_FlashDeinit(); | |
| 306 | |
| 307 return YAFFS_OK; | |
| 308 } | |
| 309 | |
| 310 |
