Blame view
common/flash.c
5.54 KB
affae2bff
|
1 2 3 4 |
/* * (C) Copyright 2000 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. * |
1a4596601
|
5 |
* SPDX-License-Identifier: GPL-2.0+ |
affae2bff
|
6 |
*/ |
7e780369e
|
7 |
/* #define DEBUG */ |
affae2bff
|
8 9 |
#include <common.h> #include <flash.h> |
6d0f6bcf3
|
10 |
#if !defined(CONFIG_SYS_NO_FLASH) |
ca5def3f3
|
11 |
#include <mtd/cfi_flash.h> |
affae2bff
|
12 |
|
e6f2e9023
|
13 |
extern flash_info_t flash_info[]; /* info for FLASH chips */ |
affae2bff
|
14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
/*----------------------------------------------------------------------- * Functions */ /*----------------------------------------------------------------------- * Set protection status for monitor sectors * * The monitor is always located in the _first_ Flash bank. * If necessary you have to map the second bank at lower addresses. */ void flash_protect (int flag, ulong from, ulong to, flash_info_t *info) { |
a4e8d9f5f
|
28 29 |
ulong b_end; short s_end; |
affae2bff
|
30 31 32 |
int i; /* Do nothing if input data is bad. */ |
a4e8d9f5f
|
33 |
if (!info || info->sector_count == 0 || info->size == 0 || to < from) { |
affae2bff
|
34 35 |
return; } |
a4e8d9f5f
|
36 37 |
s_end = info->sector_count - 1; /* index of last sector */ b_end = info->start[0] + info->size - 1; /* bank end address */ |
d2f680066
|
38 39 40 41 42 |
debug ("flash_protect %s: from 0x%08lX to 0x%08lX ", (flag & FLAG_PROTECT_SET) ? "ON" : (flag & FLAG_PROTECT_CLEAR) ? "OFF" : "???", from, to); |
affae2bff
|
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
/* There is nothing to do if we have no data about the flash * or the protect range and flash range don't overlap. */ if (info->flash_id == FLASH_UNKNOWN || to < info->start[0] || from > b_end) { return; } for (i=0; i<info->sector_count; ++i) { ulong end; /* last address in current sect */ end = (i == s_end) ? b_end : info->start[i + 1] - 1; /* Update protection if any part of the sector * is in the specified range. */ if (from <= end && to >= info->start[i]) { if (flag & FLAG_PROTECT_CLEAR) { |
6d0f6bcf3
|
61 |
#if defined(CONFIG_SYS_FLASH_PROTECTION) |
affae2bff
|
62 63 64 |
flash_real_protect(info, i, 0); #else info->protect[i] = 0; |
6d0f6bcf3
|
65 |
#endif /* CONFIG_SYS_FLASH_PROTECTION */ |
7e780369e
|
66 67 |
debug ("protect off %d ", i); |
affae2bff
|
68 69 |
} else if (flag & FLAG_PROTECT_SET) { |
6d0f6bcf3
|
70 |
#if defined(CONFIG_SYS_FLASH_PROTECTION) |
affae2bff
|
71 72 73 |
flash_real_protect(info, i, 1); #else info->protect[i] = 1; |
6d0f6bcf3
|
74 |
#endif /* CONFIG_SYS_FLASH_PROTECTION */ |
7e780369e
|
75 76 |
debug ("protect on %d ", i); |
affae2bff
|
77 78 79 80 81 82 83 84 85 86 87 |
} } } } /*----------------------------------------------------------------------- */ flash_info_t * addr2info (ulong addr) { |
affae2bff
|
88 89 |
flash_info_t *info; int i; |
6d0f6bcf3
|
90 |
for (i=0, info = &flash_info[0]; i<CONFIG_SYS_MAX_FLASH_BANKS; ++i, ++info) { |
affae2bff
|
91 92 93 94 95 96 97 98 99 100 101 |
if (info->flash_id != FLASH_UNKNOWN && addr >= info->start[0] && /* WARNING - The '- 1' is needed if the flash * is at the end of the address space, since * info->start[0] + info->size wraps back to 0. * Please don't change this unless you understand this. */ addr <= info->start[0] + info->size - 1) { return (info); } } |
affae2bff
|
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 |
return (NULL); } /*----------------------------------------------------------------------- * Copy memory to flash. * Make sure all target addresses are within Flash bounds, * and no protected sectors are hit. * Returns: * ERR_OK 0 - OK * ERR_TIMOUT 1 - write timeout * ERR_NOT_ERASED 2 - Flash not erased * ERR_PROTECTED 4 - target range includes protected sectors * ERR_INVAL 8 - target address not in Flash memory * ERR_ALIGN 16 - target address not aligned on boundary * (only some targets require alignment) */ int |
77ddac948
|
120 |
flash_write (char *src, ulong addr, ulong cnt) |
affae2bff
|
121 |
{ |
affae2bff
|
122 123 124 125 126 |
int i; ulong end = addr + cnt - 1; flash_info_t *info_first = addr2info (addr); flash_info_t *info_last = addr2info (end ); flash_info_t *info; |
352ef3f1b
|
127 128 129 |
__maybe_unused char *src_orig = src; __maybe_unused char *addr_orig = (char *)addr; __maybe_unused ulong cnt_orig = cnt; |
affae2bff
|
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 |
if (cnt == 0) { return (ERR_OK); } if (!info_first || !info_last) { return (ERR_INVAL); } for (info = info_first; info <= info_last; ++info) { ulong b_end = info->start[0] + info->size; /* bank end addr */ short s_end = info->sector_count - 1; for (i=0; i<info->sector_count; ++i) { ulong e_addr = (i == s_end) ? b_end : info->start[i + 1]; if ((end >= info->start[i]) && (addr < e_addr) && (info->protect[i] != 0) ) { return (ERR_PROTECTED); } } } /* finally write data to flash */ for (info = info_first; info <= info_last && cnt>0; ++info) { ulong len; len = info->start[0] + info->size - addr; if (len > cnt) len = cnt; |
77ddac948
|
159 |
if ((i = write_buff(info, (uchar *)src, addr, len)) != 0) { |
affae2bff
|
160 161 162 163 164 165 |
return (i); } cnt -= len; addr += len; src += len; } |
352ef3f1b
|
166 167 168 169 170 171 172 173 174 |
#if defined(CONFIG_FLASH_VERIFY) if (memcmp(src_orig, addr_orig, cnt_orig)) { printf(" Verify failed! "); return ERR_PROG_ERROR; } #endif /* CONFIG_SYS_FLASH_VERIFY_AFTER_WRITE */ |
affae2bff
|
175 |
return (ERR_OK); |
affae2bff
|
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 |
} /*----------------------------------------------------------------------- */ void flash_perror (int err) { switch (err) { case ERR_OK: break; case ERR_TIMOUT: puts ("Timeout writing to Flash "); break; case ERR_NOT_ERASED: puts ("Flash not Erased "); break; case ERR_PROTECTED: puts ("Can't write to protected Flash sectors "); break; case ERR_INVAL: puts ("Outside available Flash "); break; case ERR_ALIGN: puts ("Start and/or end address not on sector boundary "); break; case ERR_UNKNOWN_FLASH_VENDOR: puts ("Unknown Vendor of Flash "); break; case ERR_UNKNOWN_FLASH_TYPE: puts ("Unknown Type of Flash "); break; case ERR_PROG_ERROR: puts ("General Flash Programming Error "); break; |
de15a06aa
|
218 219 220 221 |
case ERR_ABORTED: puts("Flash Programming Aborted "); break; |
affae2bff
|
222 223 224 225 226 227 228 229 230 |
default: printf ("%s[%d] FIXME: rc=%d ", __FILE__, __LINE__, err); break; } } /*----------------------------------------------------------------------- */ |
6d0f6bcf3
|
231 |
#endif /* !CONFIG_SYS_NO_FLASH */ |