]>
Commit | Line | Data |
---|---|---|
3e38691e WD |
1 | /* |
2 | * Copyright (C) 2003 ETC s.r.o. | |
3 | * | |
4 | * This code was inspired by Marius Groeger and Kyle Harris code | |
5 | * available in other board ports for U-Boot | |
6 | * | |
7 | * See file CREDITS for list of people who contributed to this | |
8 | * project. | |
9 | * | |
10 | * This program is free software; you can redistribute it and/or | |
11 | * modify it under the terms of the GNU General Public License as | |
12 | * published by the Free Software Foundation; either version 2 of | |
13 | * the License, or (at your option) any later version. | |
14 | * | |
15 | * This program is distributed in the hope that it will be useful, | |
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
18 | * GNU General Public License for more details. | |
19 | * | |
20 | * You should have received a copy of the GNU General Public License | |
21 | * along with this program; if not, write to the Free Software | |
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
23 | * MA 02111-1307 USA | |
24 | * | |
25 | * Written by Peter Figuli <peposh@etc.sk>, 2003. | |
26 | * | |
27 | */ | |
28 | ||
29 | #include <common.h> | |
30 | #include "intel.h" | |
31 | ||
32 | ||
33 | /* | |
34 | * This code should handle CFI FLASH memory device. This code is very | |
35 | * minimalistic approach without many essential error handling code as well. | |
36 | * Because U-Boot actually is missing smart handling of FLASH device, | |
37 | * we just set flash_id to anything else to FLASH_UNKNOW, so common code | |
38 | * can call us without any restrictions. | |
39 | * TODO: Add CFI Query, to be able to determine FLASH device. | |
40 | * TODO: Add error handling code | |
41 | * NOTE: This code was tested with BUS_WIDTH 4 and ITERLEAVE 2 only, but | |
42 | * hopefully may work with other configurations. | |
43 | */ | |
44 | ||
45 | #if ( WEP_FLASH_BUS_WIDTH == 1 ) | |
46 | # define FLASH_BUS vu_char | |
47 | # if ( WEP_FLASH_INTERLEAVE == 1 ) | |
48 | # define FLASH_CMD( x ) x | |
49 | # else | |
50 | # error "With 8bit bus only one chip is allowed" | |
51 | # endif | |
52 | ||
53 | ||
54 | #elif ( WEP_FLASH_BUS_WIDTH == 2 ) | |
55 | # define FLASH_BUS vu_short | |
56 | # if ( WEP_FLASH_INTERLEAVE == 1 ) | |
57 | # define FLASH_CMD( x ) x | |
58 | # elif ( WEP_FLASH_INTERLEAVE == 2 ) | |
59 | # define FLASH_CMD( x ) (( x << 8 )| x ) | |
60 | # else | |
61 | # error "With 16bit bus only 1 or 2 chip(s) are allowed" | |
62 | # endif | |
63 | ||
64 | ||
65 | #elif ( WEP_FLASH_BUS_WIDTH == 4 ) | |
66 | # define FLASH_BUS vu_long | |
67 | # if ( WEP_FLASH_INTERLEAVE == 1 ) | |
68 | # define FLASH_CMD( x ) x | |
69 | # elif ( WEP_FLASH_INTERLEAVE == 2 ) | |
70 | # define FLASH_CMD( x ) (( x << 16 )| x ) | |
71 | # elif ( WEP_FLASH_INTERLEAVE == 4 ) | |
72 | # define FLASH_CMD( x ) (( x << 24 )|( x << 16 ) ( x << 8 )| x ) | |
73 | # else | |
74 | # error "With 32bit bus only 1,2 or 4 chip(s) are allowed" | |
75 | # endif | |
76 | ||
77 | #else | |
78 | # error "Flash bus width might be 1,2,4 for 8,16,32 bit configuration" | |
79 | #endif | |
80 | ||
81 | ||
82 | flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; | |
83 | ||
84 | static FLASH_BUS flash_status_reg (void) | |
85 | { | |
86 | ||
87 | FLASH_BUS *addr = (FLASH_BUS *) 0; | |
88 | ||
89 | *addr = FLASH_CMD (CFI_INTEL_CMD_READ_STATUS_REGISTER); | |
90 | ||
91 | return *addr; | |
92 | } | |
93 | ||
94 | static int flash_ready (ulong timeout) | |
95 | { | |
96 | int ok = 1; | |
97 | ||
98 | reset_timer_masked (); | |
99 | while ((flash_status_reg () & FLASH_CMD (CFI_INTEL_SR_READY)) != | |
100 | FLASH_CMD (CFI_INTEL_SR_READY)) { | |
101 | if (get_timer_masked () > timeout && timeout != 0) { | |
102 | ok = 0; | |
103 | break; | |
104 | } | |
105 | } | |
106 | return ok; | |
107 | } | |
108 | ||
109 | #if ( CFG_MAX_FLASH_BANKS != 1 ) | |
110 | # error "WEP platform has only one flash bank!" | |
111 | #endif | |
112 | ||
113 | ||
114 | ulong flash_init (void) | |
115 | { | |
116 | int i; | |
117 | FLASH_BUS address = WEP_FLASH_BASE; | |
118 | ||
119 | flash_info[0].size = WEP_FLASH_BANK_SIZE; | |
120 | flash_info[0].sector_count = CFG_MAX_FLASH_SECT; | |
121 | flash_info[0].flash_id = INTEL_MANUFACT; | |
122 | memset (flash_info[0].protect, 0, CFG_MAX_FLASH_SECT); | |
123 | ||
124 | for (i = 0; i < CFG_MAX_FLASH_SECT; i++) { | |
125 | flash_info[0].start[i] = address; | |
126 | #ifdef WEP_FLASH_UNLOCK | |
127 | /* Some devices are hw locked after start. */ | |
128 | *((FLASH_BUS *) address) = FLASH_CMD (CFI_INTEL_CMD_LOCK_SETUP); | |
129 | *((FLASH_BUS *) address) = FLASH_CMD (CFI_INTEL_CMD_UNLOCK_BLOCK); | |
130 | flash_ready (0); | |
131 | *((FLASH_BUS *) address) = FLASH_CMD (CFI_INTEL_CMD_READ_ARRAY); | |
132 | #endif | |
133 | address += WEP_FLASH_SECT_SIZE; | |
134 | } | |
135 | ||
136 | flash_protect (FLAG_PROTECT_SET, | |
137 | CFG_FLASH_BASE, | |
3b57fe0a | 138 | CFG_FLASH_BASE + monitor_flash_len - 1, |
3e38691e WD |
139 | &flash_info[0]); |
140 | ||
141 | flash_protect (FLAG_PROTECT_SET, | |
142 | CFG_ENV_ADDR, | |
143 | CFG_ENV_ADDR + CFG_ENV_SIZE - 1, &flash_info[0]); | |
144 | ||
145 | return WEP_FLASH_BANK_SIZE; | |
146 | } | |
147 | ||
148 | void flash_print_info (flash_info_t * info) | |
149 | { | |
150 | int i; | |
151 | ||
152 | printf (" Intel vendor\n"); | |
153 | printf (" Size: %ld MB in %d Sectors\n", | |
154 | info->size >> 20, info->sector_count); | |
155 | ||
156 | printf (" Sector Start Addresses:"); | |
157 | for (i = 0; i < info->sector_count; i++) { | |
158 | if (!(i % 5)) { | |
159 | printf ("\n"); | |
160 | } | |
161 | ||
162 | printf (" %08lX%s", info->start[i], | |
163 | info->protect[i] ? " (RO)" : " "); | |
164 | } | |
165 | printf ("\n"); | |
166 | } | |
167 | ||
168 | ||
169 | int flash_erase (flash_info_t * info, int s_first, int s_last) | |
170 | { | |
171 | int flag, non_protected = 0, sector; | |
172 | int rc = ERR_OK; | |
173 | ||
174 | FLASH_BUS *address; | |
175 | ||
176 | for (sector = s_first; sector <= s_last; sector++) { | |
177 | if (!info->protect[sector]) { | |
178 | non_protected++; | |
179 | } | |
180 | } | |
181 | ||
182 | if (!non_protected) { | |
183 | return ERR_PROTECTED; | |
184 | } | |
185 | ||
186 | /* | |
187 | * Disable interrupts which might cause a timeout | |
188 | * here. Remember that our exception vectors are | |
189 | * at address 0 in the flash, and we don't want a | |
190 | * (ticker) exception to happen while the flash | |
191 | * chip is in programming mode. | |
192 | */ | |
193 | flag = disable_interrupts (); | |
194 | ||
195 | ||
196 | /* Start erase on unprotected sectors */ | |
197 | for (sector = s_first; sector <= s_last && !ctrlc (); sector++) { | |
198 | if (info->protect[sector]) { | |
199 | printf ("Protected sector %2d skipping...\n", sector); | |
200 | continue; | |
201 | } else { | |
202 | printf ("Erasing sector %2d ... ", sector); | |
203 | } | |
8bde7f77 | 204 | |
3e38691e WD |
205 | address = (FLASH_BUS *) (info->start[sector]); |
206 | ||
207 | *address = FLASH_CMD (CFI_INTEL_CMD_BLOCK_ERASE); | |
208 | *address = FLASH_CMD (CFI_INTEL_CMD_CONFIRM); | |
209 | if (flash_ready (CFG_FLASH_ERASE_TOUT)) { | |
210 | *address = FLASH_CMD (CFI_INTEL_CMD_CLEAR_STATUS_REGISTER); | |
211 | printf ("ok.\n"); | |
212 | } else { | |
213 | *address = FLASH_CMD (CFI_INTEL_CMD_SUSPEND); | |
214 | rc = ERR_TIMOUT; | |
215 | printf ("timeout! Aborting...\n"); | |
216 | break; | |
217 | } | |
218 | *address = FLASH_CMD (CFI_INTEL_CMD_READ_ARRAY); | |
219 | } | |
220 | if (ctrlc ()) | |
221 | printf ("User Interrupt!\n"); | |
222 | ||
223 | /* allow flash to settle - wait 10 ms */ | |
224 | udelay_masked (10000); | |
225 | if (flag) { | |
226 | enable_interrupts (); | |
227 | } | |
228 | ||
229 | return rc; | |
230 | } | |
231 | ||
232 | static int write_data (flash_info_t * info, ulong dest, FLASH_BUS data) | |
233 | { | |
234 | FLASH_BUS *address = (FLASH_BUS *) dest; | |
235 | int rc = ERR_OK; | |
236 | int flag; | |
237 | ||
238 | /* Check if Flash is (sufficiently) erased */ | |
239 | if ((*address & data) != data) { | |
240 | return ERR_NOT_ERASED; | |
241 | } | |
242 | ||
243 | /* | |
244 | * Disable interrupts which might cause a timeout | |
245 | * here. Remember that our exception vectors are | |
246 | * at address 0 in the flash, and we don't want a | |
247 | * (ticker) exception to happen while the flash | |
248 | * chip is in programming mode. | |
249 | */ | |
250 | ||
251 | flag = disable_interrupts (); | |
252 | ||
253 | *address = FLASH_CMD (CFI_INTEL_CMD_CLEAR_STATUS_REGISTER); | |
254 | *address = FLASH_CMD (CFI_INTEL_CMD_PROGRAM1); | |
255 | *address = data; | |
256 | ||
257 | if (!flash_ready (CFG_FLASH_WRITE_TOUT)) { | |
258 | *address = FLASH_CMD (CFI_INTEL_CMD_SUSPEND); | |
259 | rc = ERR_TIMOUT; | |
260 | printf ("timeout! Aborting...\n"); | |
261 | } | |
262 | ||
263 | *address = FLASH_CMD (CFI_INTEL_CMD_READ_ARRAY); | |
264 | if (flag) { | |
265 | enable_interrupts (); | |
266 | } | |
267 | ||
268 | return rc; | |
269 | } | |
270 | ||
271 | int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt) | |
272 | { | |
273 | ulong read_addr, write_addr; | |
274 | FLASH_BUS data; | |
275 | int i, result = ERR_OK; | |
276 | ||
277 | ||
278 | read_addr = addr & ~(sizeof (FLASH_BUS) - 1); | |
279 | write_addr = read_addr; | |
280 | if (read_addr != addr) { | |
281 | data = 0; | |
282 | for (i = 0; i < sizeof (FLASH_BUS); i++) { | |
283 | if (read_addr < addr || cnt == 0) { | |
284 | data |= *((uchar *) read_addr) << i * 8; | |
285 | } else { | |
286 | data |= (*src++) << i * 8; | |
287 | cnt--; | |
288 | } | |
289 | read_addr++; | |
290 | } | |
291 | if ((result = write_data (info, write_addr, data)) != ERR_OK) { | |
292 | return result; | |
293 | } | |
294 | write_addr += sizeof (FLASH_BUS); | |
295 | } | |
296 | for (; cnt >= sizeof (FLASH_BUS); cnt -= sizeof (FLASH_BUS)) { | |
297 | if ((result = write_data (info, write_addr, | |
298 | *((FLASH_BUS *) src))) != ERR_OK) { | |
299 | return result; | |
300 | } | |
301 | write_addr += sizeof (FLASH_BUS); | |
302 | src += sizeof (FLASH_BUS); | |
303 | } | |
304 | if (cnt > 0) { | |
305 | read_addr = write_addr; | |
306 | data = 0; | |
307 | for (i = 0; i < sizeof (FLASH_BUS); i++) { | |
308 | if (cnt > 0) { | |
309 | data |= (*src++) << i * 8; | |
310 | cnt--; | |
311 | } else { | |
312 | data |= *((uchar *) read_addr) << i * 8; | |
313 | } | |
314 | read_addr++; | |
315 | } | |
316 | if ((result = write_data (info, write_addr, data)) != 0) { | |
317 | return result; | |
318 | } | |
319 | } | |
320 | return ERR_OK; | |
321 | } |