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 #include "yportenv.h" 18 19 20 #include "yaffs_mtdif.h" 21 22 #include "linux/mtd/mtd.h" 23 #include "linux/types.h" 24 #include "linux/time.h" 25 #include "linux/mtd/nand.h" 26 27 28 static inline void translate_spare2oob(const struct yaffs_spare *spare, u8 *oob) 29 { 30 oob[0] = spare->tb0; 31 oob[1] = spare->tb1; 32 oob[2] = spare->tb2; 33 oob[3] = spare->tb3; 34 oob[4] = spare->tb4; 35 oob[5] = spare->tb5 & 0x3f; 36 oob[5] |= spare->block_status == 'Y' ? 0 : 0x80; 37 oob[5] |= spare->page_status == 0 ? 0 : 0x40; 38 oob[6] = spare->tb6; 39 oob[7] = spare->tb7; 40 } 41 42 static inline void translate_oob2spare(struct yaffs_spare *spare, u8 *oob) 43 { 44 struct yaffs_nand_spare *nspare = (struct yaffs_nand_spare *)spare; 45 spare->tb0 = oob[0]; 46 spare->tb1 = oob[1]; 47 spare->tb2 = oob[2]; 48 spare->tb3 = oob[3]; 49 spare->tb4 = oob[4]; 50 spare->tb5 = oob[5] == 0xff ? 0xff : oob[5] & 0x3f; 51 spare->block_status = oob[5] & 0x80 ? 0xff : 'Y'; 52 spare->page_status = oob[5] & 0x40 ? 0xff : 0; 53 spare->ecc1[0] = spare->ecc1[1] = spare->ecc1[2] = 0xff; 54 spare->tb6 = oob[6]; 55 spare->tb7 = oob[7]; 56 spare->ecc2[0] = spare->ecc2[1] = spare->ecc2[2] = 0xff; 57 58 nspare->eccres1 = nspare->eccres2 = 0; /* FIXME */ 59 } 60 61 62 int nandmtd_WriteChunkToNAND(struct yaffs_dev *dev, int chunkInNAND, 63 const u8 *data, const struct yaffs_spare *spare) 64 { 65 struct mtd_info *mtd = (struct mtd_info *)(dev->driver_context); 66 struct mtd_oob_ops ops; 67 size_t dummy; 68 int retval = 0; 69 loff_t addr = ((loff_t) chunkInNAND) * dev->data_bytes_per_chunk; 70 u8 spareAsBytes[8]; /* OOB */ 71 72 if (data && !spare) 73 retval = mtd->write(mtd, addr, dev->data_bytes_per_chunk, 74 &dummy, data); 75 else if (spare) { 76 if (dev->param.use_nand_ecc) { 77 translate_spare2oob(spare, spareAsBytes); 78 ops.mode = MTD_OOB_AUTO; 79 ops.ooblen = 8; /* temp hack */ 80 } else { 81 ops.mode = MTD_OOB_RAW; 82 ops.ooblen = YAFFS_BYTES_PER_SPARE; 83 } 84 ops.len = data ? dev->data_bytes_per_chunk : ops.ooblen; 85 ops.datbuf = (u8 *)data; 86 ops.ooboffs = 0; 87 ops.oobbuf = spareAsBytes; 88 retval = mtd->write_oob(mtd, addr, &ops); 89 } 90 91 if (retval == 0) 92 return YAFFS_OK; 93 else 94 return YAFFS_FAIL; 95 } 96 97 int nandmtd_ReadChunkFromNAND(struct yaffs_dev *dev, int chunkInNAND, u8 *data, 98 struct yaffs_spare *spare) 99 { 100 struct mtd_info *mtd = (struct mtd_info *)(dev->driver_context); 101 struct mtd_oob_ops ops; 102 size_t dummy; 103 int retval = 0; 104 105 loff_t addr = ((loff_t) chunkInNAND) * dev->data_bytes_per_chunk; 106 u8 spareAsBytes[8]; /* OOB */ 107 108 if (data && !spare) 109 retval = mtd->read(mtd, addr, dev->data_bytes_per_chunk, 110 &dummy, data); 111 else if (spare) { 112 if (dev->param.use_nand_ecc) { 113 ops.mode = MTD_OOB_AUTO; 114 ops.ooblen = 8; /* temp hack */ 115 } else { 116 ops.mode = MTD_OOB_RAW; 117 ops.ooblen = YAFFS_BYTES_PER_SPARE; 118 } 119 ops.len = data ? dev->data_bytes_per_chunk : ops.ooblen; 120 ops.datbuf = data; 121 ops.ooboffs = 0; 122 ops.oobbuf = spareAsBytes; 123 retval = mtd->read_oob(mtd, addr, &ops); 124 if (dev->param.use_nand_ecc) 125 translate_oob2spare(spare, spareAsBytes); 126 } 127 128 if (retval == 0) 129 return YAFFS_OK; 130 else 131 return YAFFS_FAIL; 132 } 133 134 int nandmtd_EraseBlockInNAND(struct yaffs_dev *dev, int blockNumber) 135 { 136 struct mtd_info *mtd = (struct mtd_info *)(dev->driver_context); 137 __u32 addr = 138 ((loff_t) blockNumber) * dev->data_bytes_per_chunk 139 * dev->param.chunks_per_block; 140 struct erase_info ei; 141 int retval = 0; 142 143 ei.mtd = mtd; 144 ei.addr = addr; 145 ei.len = dev->data_bytes_per_chunk * dev->param.chunks_per_block; 146 ei.time = 1000; 147 ei.retries = 2; 148 ei.callback = NULL; 149 ei.priv = (u_long) dev; 150 151 /* Todo finish off the ei if required */ 152 153 154 retval = mtd->erase(mtd, &ei); 155 156 if (retval == 0) 157 return YAFFS_OK; 158 else 159 return YAFFS_FAIL; 160 } 161 162 int nandmtd_InitialiseNAND(struct yaffs_dev *dev) 163 { 164 return YAFFS_OK; 165 } 166