1 /* 2 * (C) Copyright 2008 Semihalf 3 * 4 * Written by: Piotr Ziecik <kosmo@semihalf.com> 5 * 6 * See file CREDITS for list of people who contributed to this 7 * project. 8 * 9 * This program is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU General Public License as 11 * published by the Free Software Foundation; either version 2 of 12 * the License, or (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program; if not, write to the Free Software 21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 22 * MA 02111-1307 USA 23 * 24 */ 25 26 #include <common.h> 27 #include <flash.h> 28 29 #include <asm/errno.h> 30 #include <linux/mtd/mtd.h> 31 32 extern flash_info_t flash_info[]; 33 34 static struct mtd_info cfi_mtd_info[CONFIG_SYS_MAX_FLASH_BANKS]; 35 static char cfi_mtd_names[CONFIG_SYS_MAX_FLASH_BANKS][16]; 36 37 static int cfi_mtd_erase(struct mtd_info *mtd, struct erase_info *instr) 38 { 39 flash_info_t *fi = mtd->priv; 40 size_t a_start = fi->start[0] + instr->addr; 41 size_t a_end = a_start + instr->len; 42 int s_first = -1; 43 int s_last = -1; 44 int error, sect; 45 46 for (sect = 0; sect < fi->sector_count - 1; sect++) { 47 if (a_start == fi->start[sect]) 48 s_first = sect; 49 50 if (a_end == fi->start[sect + 1]) { 51 s_last = sect; 52 break; 53 } 54 } 55 56 if (s_first >= 0 && s_first <= s_last) { 57 instr->state = MTD_ERASING; 58 59 flash_set_verbose(0); 60 error = flash_erase(fi, s_first, s_last); 61 flash_set_verbose(1); 62 63 if (error) { 64 instr->state = MTD_ERASE_FAILED; 65 return -EIO; 66 } 67 68 instr->state = MTD_ERASE_DONE; 69 mtd_erase_callback(instr); 70 return 0; 71 } 72 73 return -EINVAL; 74 } 75 76 static int cfi_mtd_read(struct mtd_info *mtd, loff_t from, size_t len, 77 size_t *retlen, u_char *buf) 78 { 79 flash_info_t *fi = mtd->priv; 80 u_char *f = (u_char*)(fi->start[0]) + from; 81 82 memcpy(buf, f, len); 83 *retlen = len; 84 85 return 0; 86 } 87 88 static int cfi_mtd_write(struct mtd_info *mtd, loff_t to, size_t len, 89 size_t *retlen, const u_char *buf) 90 { 91 flash_info_t *fi = mtd->priv; 92 u_long t = fi->start[0] + to; 93 int error; 94 95 flash_set_verbose(0); 96 error = write_buff(fi, (u_char*)buf, t, len); 97 flash_set_verbose(1); 98 99 if (!error) { 100 *retlen = len; 101 return 0; 102 } 103 104 return -EIO; 105 } 106 107 static void cfi_mtd_sync(struct mtd_info *mtd) 108 { 109 /* 110 * This function should wait until all pending operations 111 * finish. However this driver is fully synchronous, so 112 * this function returns immediately 113 */ 114 } 115 116 static int cfi_mtd_lock(struct mtd_info *mtd, loff_t ofs, size_t len) 117 { 118 flash_info_t *fi = mtd->priv; 119 120 flash_set_verbose(0); 121 flash_protect(FLAG_PROTECT_SET, fi->start[0] + ofs, 122 fi->start[0] + ofs + len - 1, fi); 123 flash_set_verbose(1); 124 125 return 0; 126 } 127 128 static int cfi_mtd_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) 129 { 130 flash_info_t *fi = mtd->priv; 131 132 flash_set_verbose(0); 133 flash_protect(FLAG_PROTECT_CLEAR, fi->start[0] + ofs, 134 fi->start[0] + ofs + len - 1, fi); 135 flash_set_verbose(1); 136 137 return 0; 138 } 139 140 static int cfi_mtd_set_erasesize(struct mtd_info *mtd, flash_info_t *fi) 141 { 142 int sect_size = 0; 143 int sect; 144 145 /* 146 * Select the largest sector size as erasesize (e.g. for UBI) 147 */ 148 for (sect = 0; sect < fi->sector_count; sect++) { 149 if (flash_sector_size(fi, sect) > sect_size) 150 sect_size = flash_sector_size(fi, sect); 151 } 152 153 mtd->erasesize = sect_size; 154 155 return 0; 156 } 157 158 int cfi_mtd_init(void) 159 { 160 struct mtd_info *mtd; 161 flash_info_t *fi; 162 int error, i; 163 164 for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) { 165 fi = &flash_info[i]; 166 mtd = &cfi_mtd_info[i]; 167 168 memset(mtd, 0, sizeof(struct mtd_info)); 169 170 error = cfi_mtd_set_erasesize(mtd, fi); 171 if (error) 172 continue; 173 174 sprintf(cfi_mtd_names[i], "nor%d", i); 175 mtd->name = cfi_mtd_names[i]; 176 mtd->type = MTD_NORFLASH; 177 mtd->flags = MTD_CAP_NORFLASH; 178 mtd->size = fi->size; 179 mtd->writesize = 1; 180 181 mtd->erase = cfi_mtd_erase; 182 mtd->read = cfi_mtd_read; 183 mtd->write = cfi_mtd_write; 184 mtd->sync = cfi_mtd_sync; 185 mtd->lock = cfi_mtd_lock; 186 mtd->unlock = cfi_mtd_unlock; 187 mtd->priv = fi; 188 189 if (add_mtd_device(mtd)) 190 return -ENOMEM; 191 } 192 193 return 0; 194 } 195