Revisión | ea8015b852305387b379a88d256ffe80d373d20a (tree) |
---|---|
Tiempo | 2002-10-27 01:43:06 |
Autor | wdenk <wdenk> |
Commiter | wdenk |
Initial revision
@@ -0,0 +1,367 @@ | ||
1 | +/* | |
2 | + * (C) Copyright 2002 | |
3 | + * Kyle Harris, Nexus Technologies, Inc. kharris@nexus-tech.net | |
4 | + * | |
5 | + * (C) Copyright 2002 | |
6 | + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> | |
7 | + * Marius Groeger <mgroeger@sysgo.de> | |
8 | + * | |
9 | + * See file CREDITS for list of people who contributed to this | |
10 | + * project. | |
11 | + * | |
12 | + * This program is free software; you can redistribute it and/or | |
13 | + * modify it under the terms of the GNU General Public License as | |
14 | + * published by the Free Software Foundation; either version 2 of | |
15 | + * the License, or (at your option) any later version. | |
16 | + * | |
17 | + * This program is distributed in the hope that it will be useful, | |
18 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
19 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
20 | + * GNU General Public License for more details. | |
21 | + * | |
22 | + * You should have received a copy of the GNU General Public License | |
23 | + * along with this program; if not, write to the Free Software | |
24 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
25 | + * MA 02111-1307 USA | |
26 | + */ | |
27 | + | |
28 | +#include <common.h> | |
29 | + | |
30 | +#define FLASH_BANK_SIZE 0x400000 | |
31 | +#define MAIN_SECT_SIZE 0x20000 | |
32 | + | |
33 | +flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; | |
34 | + | |
35 | + | |
36 | +/*----------------------------------------------------------------------- | |
37 | + */ | |
38 | + | |
39 | +ulong flash_init(void) | |
40 | +{ | |
41 | + int i, j; | |
42 | + ulong size = 0; | |
43 | + | |
44 | + for (i = 0; i < CFG_MAX_FLASH_BANKS; i++) | |
45 | + { | |
46 | + ulong flashbase = 0; | |
47 | + flash_info[i].flash_id = | |
48 | + (INTEL_MANUFACT & FLASH_VENDMASK) | | |
49 | + (INTEL_ID_28F128J3 & FLASH_TYPEMASK); | |
50 | + flash_info[i].size = FLASH_BANK_SIZE; | |
51 | + flash_info[i].sector_count = CFG_MAX_FLASH_SECT; | |
52 | + memset(flash_info[i].protect, 0, CFG_MAX_FLASH_SECT); | |
53 | + switch (i) | |
54 | + { | |
55 | + case 0: | |
56 | + flashbase = PHYS_FLASH_1; | |
57 | + break; | |
58 | + case 1: | |
59 | + flashbase = PHYS_FLASH_2; | |
60 | + break; | |
61 | + default: | |
62 | + panic("configured to many flash banks!\n"); | |
63 | + break; | |
64 | + } | |
65 | + for (j = 0; j < flash_info[i].sector_count; j++) | |
66 | + { | |
67 | + flash_info[i].start[j] = flashbase + j*MAIN_SECT_SIZE; | |
68 | + } | |
69 | + size += flash_info[i].size; | |
70 | + } | |
71 | + | |
72 | + /* Protect monitor and environment sectors | |
73 | + */ | |
74 | + flash_protect(FLAG_PROTECT_SET, | |
75 | + CFG_FLASH_BASE, | |
76 | + CFG_FLASH_BASE + _armboot_end_data - _armboot_start, | |
77 | + &flash_info[0]); | |
78 | + | |
79 | + flash_protect(FLAG_PROTECT_SET, | |
80 | + CFG_ENV_ADDR, | |
81 | + CFG_ENV_ADDR + CFG_ENV_SIZE - 1, | |
82 | + &flash_info[0]); | |
83 | + | |
84 | + return size; | |
85 | +} | |
86 | + | |
87 | +/*----------------------------------------------------------------------- | |
88 | + */ | |
89 | +void flash_print_info (flash_info_t *info) | |
90 | +{ | |
91 | + int i, j; | |
92 | + | |
93 | + for (j=0; j<CFG_MAX_FLASH_BANKS; j++) | |
94 | + { | |
95 | + switch (info->flash_id & FLASH_VENDMASK) | |
96 | + { | |
97 | + case (INTEL_MANUFACT & FLASH_VENDMASK): | |
98 | + printf("Intel: "); | |
99 | + break; | |
100 | + default: | |
101 | + printf("Unknown Vendor "); | |
102 | + break; | |
103 | + } | |
104 | + | |
105 | + switch (info->flash_id & FLASH_TYPEMASK) | |
106 | + { | |
107 | + case (INTEL_ID_28F320J3A & FLASH_TYPEMASK): | |
108 | + printf("28F320J3A (32Mbit)\n"); | |
109 | + break; | |
110 | + case (INTEL_ID_28F128J3 & FLASH_TYPEMASK): | |
111 | + printf("28F128J3 (128Mbit)\n"); | |
112 | + break; | |
113 | + default: | |
114 | + printf("Unknown Chip Type\n"); | |
115 | + goto Done; | |
116 | + break; | |
117 | + } | |
118 | + | |
119 | + printf(" Size: %ld MB in %d Sectors\n", | |
120 | + info->size >> 20, info->sector_count); | |
121 | + | |
122 | + printf(" Sector Start Addresses:"); | |
123 | + for (i = 0; i < info->sector_count; i++) | |
124 | + { | |
125 | + if ((i % 5) == 0) | |
126 | + { | |
127 | + printf ("\n "); | |
128 | + } | |
129 | + printf (" %08lX%s", info->start[i], | |
130 | + info->protect[i] ? " (RO)" : " "); | |
131 | + } | |
132 | + printf ("\n"); | |
133 | + info++; | |
134 | + } | |
135 | + | |
136 | +Done: | |
137 | +} | |
138 | + | |
139 | +/*----------------------------------------------------------------------- | |
140 | + */ | |
141 | + | |
142 | +int flash_erase (flash_info_t *info, int s_first, int s_last) | |
143 | +{ | |
144 | + int flag, prot, sect; | |
145 | + int rc = ERR_OK; | |
146 | + | |
147 | + if (info->flash_id == FLASH_UNKNOWN) | |
148 | + return ERR_UNKNOWN_FLASH_TYPE; | |
149 | + | |
150 | + if ((s_first < 0) || (s_first > s_last)) { | |
151 | + return ERR_INVAL; | |
152 | + } | |
153 | + | |
154 | + if ((info->flash_id & FLASH_VENDMASK) != | |
155 | + (INTEL_MANUFACT & FLASH_VENDMASK)) { | |
156 | + return ERR_UNKNOWN_FLASH_VENDOR; | |
157 | + } | |
158 | + | |
159 | + prot = 0; | |
160 | + for (sect=s_first; sect<=s_last; ++sect) { | |
161 | + if (info->protect[sect]) { | |
162 | + prot++; | |
163 | + } | |
164 | + } | |
165 | + if (prot) | |
166 | + return ERR_PROTECTED; | |
167 | + | |
168 | + /* | |
169 | + * Disable interrupts which might cause a timeout | |
170 | + * here. Remember that our exception vectors are | |
171 | + * at address 0 in the flash, and we don't want a | |
172 | + * (ticker) exception to happen while the flash | |
173 | + * chip is in programming mode. | |
174 | + */ | |
175 | + flag = disable_interrupts(); | |
176 | + | |
177 | + /* Start erase on unprotected sectors */ | |
178 | + for (sect = s_first; sect<=s_last && !ctrlc(); sect++) { | |
179 | + | |
180 | + printf("Erasing sector %2d ... ", sect); | |
181 | + | |
182 | + /* arm simple, non interrupt dependent timer */ | |
183 | + reset_timer_masked(); | |
184 | + | |
185 | + if (info->protect[sect] == 0) { /* not protected */ | |
186 | + vu_short *addr = (vu_short *)(info->start[sect]); | |
187 | + | |
188 | + *addr = 0x20; /* erase setup */ | |
189 | + *addr = 0xD0; /* erase confirm */ | |
190 | + | |
191 | + while ((*addr & 0x80) != 0x80) { | |
192 | + if (get_timer_masked() > CFG_FLASH_ERASE_TOUT) { | |
193 | + *addr = 0xB0; /* suspend erase */ | |
194 | + *addr = 0xFF; /* reset to read mode */ | |
195 | + rc = ERR_TIMOUT; | |
196 | + goto outahere; | |
197 | + } | |
198 | + } | |
199 | + | |
200 | + /* clear status register command */ | |
201 | + *addr = 0x50; | |
202 | + /* reset to read mode */ | |
203 | + *addr = 0xFF; | |
204 | + } | |
205 | + printf("ok.\n"); | |
206 | + } | |
207 | + if (ctrlc()) | |
208 | + printf("User Interrupt!\n"); | |
209 | + | |
210 | +outahere: | |
211 | + | |
212 | + /* allow flash to settle - wait 10 ms */ | |
213 | + udelay_masked(10000); | |
214 | + | |
215 | + if (flag) | |
216 | + enable_interrupts(); | |
217 | + | |
218 | + return rc; | |
219 | +} | |
220 | + | |
221 | +/*----------------------------------------------------------------------- | |
222 | + * Copy memory to flash | |
223 | + */ | |
224 | + | |
225 | +static int write_word (flash_info_t *info, ulong dest, ushort data) | |
226 | +{ | |
227 | + vu_short *addr = (vu_short *)dest, val; | |
228 | + int rc = ERR_OK; | |
229 | + int flag; | |
230 | + | |
231 | + /* Check if Flash is (sufficiently) erased | |
232 | + */ | |
233 | + if ((*addr & data) != data) | |
234 | + return ERR_NOT_ERASED; | |
235 | + | |
236 | + /* | |
237 | + * Disable interrupts which might cause a timeout | |
238 | + * here. Remember that our exception vectors are | |
239 | + * at address 0 in the flash, and we don't want a | |
240 | + * (ticker) exception to happen while the flash | |
241 | + * chip is in programming mode. | |
242 | + */ | |
243 | + flag = disable_interrupts(); | |
244 | + | |
245 | + /* clear status register command */ | |
246 | + *addr = 0x50; | |
247 | + | |
248 | + /* program set-up command */ | |
249 | + *addr = 0x40; | |
250 | + | |
251 | + /* latch address/data */ | |
252 | + *addr = data; | |
253 | + | |
254 | + /* arm simple, non interrupt dependent timer */ | |
255 | + reset_timer_masked(); | |
256 | + | |
257 | + /* wait while polling the status register */ | |
258 | + while(((val = *addr) & 0x80) != 0x80) | |
259 | + { | |
260 | + if (get_timer_masked() > CFG_FLASH_WRITE_TOUT) { | |
261 | + rc = ERR_TIMOUT; | |
262 | + /* suspend program command */ | |
263 | + *addr = 0xB0; | |
264 | + goto outahere; | |
265 | + } | |
266 | + } | |
267 | + | |
268 | + if(val & 0x1A) { /* check for error */ | |
269 | + printf("\nFlash write error %02x at address %08lx\n", | |
270 | + (int)val, (unsigned long)dest); | |
271 | + if(val & (1<<3)) { | |
272 | + printf("Voltage range error.\n"); | |
273 | + rc = ERR_PROG_ERROR; | |
274 | + goto outahere; | |
275 | + } | |
276 | + if(val & (1<<1)) { | |
277 | + printf("Device protect error.\n"); | |
278 | + rc = ERR_PROTECTED; | |
279 | + goto outahere; | |
280 | + } | |
281 | + if(val & (1<<4)) { | |
282 | + printf("Programming error.\n"); | |
283 | + rc = ERR_PROG_ERROR; | |
284 | + goto outahere; | |
285 | + } | |
286 | + rc = ERR_PROG_ERROR; | |
287 | + goto outahere; | |
288 | + } | |
289 | + | |
290 | +outahere: | |
291 | + /* read array command */ | |
292 | + *addr = 0xFF; | |
293 | + | |
294 | + if (flag) | |
295 | + enable_interrupts(); | |
296 | + | |
297 | + return rc; | |
298 | +} | |
299 | + | |
300 | +/*----------------------------------------------------------------------- | |
301 | + * Copy memory to flash. | |
302 | + */ | |
303 | + | |
304 | +int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt) | |
305 | +{ | |
306 | + ulong cp, wp; | |
307 | + ushort data; | |
308 | + int l; | |
309 | + int i, rc; | |
310 | + | |
311 | + wp = (addr & ~1); /* get lower word aligned address */ | |
312 | + | |
313 | + /* | |
314 | + * handle unaligned start bytes | |
315 | + */ | |
316 | + if ((l = addr - wp) != 0) | |
317 | + { | |
318 | + data = 0; | |
319 | + for (i=0, cp=wp; i<l; ++i, ++cp) { | |
320 | + data = (data >> 8) | (*(uchar *)cp << 8); | |
321 | + } | |
322 | + for (; i<2 && cnt>0; ++i) { | |
323 | + data = (data >> 8) | (*src++ << 8); | |
324 | + --cnt; | |
325 | + ++cp; | |
326 | + } | |
327 | + for (; cnt==0 && i<2; ++i, ++cp) { | |
328 | + data = (data >> 8) | (*(uchar *)cp << 8); | |
329 | + } | |
330 | + | |
331 | + if ((rc = write_word(info, wp, data)) != 0) { | |
332 | + return (rc); | |
333 | + } | |
334 | + wp += 2; | |
335 | + } | |
336 | + | |
337 | + /* | |
338 | + * handle word aligned part | |
339 | + */ | |
340 | + while (cnt >= 2) { | |
341 | + data = *((vu_short*)src); | |
342 | + if ((rc = write_word(info, wp, data)) != 0) { | |
343 | + return (rc); | |
344 | + } | |
345 | + src += 2; | |
346 | + wp += 2; | |
347 | + cnt -= 2; | |
348 | + } | |
349 | + | |
350 | + if (cnt == 0) { | |
351 | + return ERR_OK; | |
352 | + } | |
353 | + | |
354 | + /* | |
355 | + * handle unaligned tail bytes | |
356 | + */ | |
357 | + data = 0; | |
358 | + for (i=0, cp=wp; i<2 && cnt>0; ++i, ++cp) { | |
359 | + data = (data >> 8) | (*src++ << 8); | |
360 | + --cnt; | |
361 | + } | |
362 | + for (; i<2; ++i, ++cp) { | |
363 | + data = (data >> 8) | (*(uchar *)cp << 8); | |
364 | + } | |
365 | + | |
366 | + return write_word(info, wp, data); | |
367 | +} |
@@ -0,0 +1,473 @@ | ||
1 | +/* | |
2 | + * (C) Copyright 2002 | |
3 | + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> | |
4 | + * Rolf Offermanns <rof@sysgo.de> | |
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 | +#include <common.h> | |
26 | + | |
27 | +ulong myflush(void); | |
28 | + | |
29 | + | |
30 | +#define FLASH_BANK_SIZE 0x800000 | |
31 | +#define MAIN_SECT_SIZE 0x20000 | |
32 | +#define PARAM_SECT_SIZE 0x4000 | |
33 | + | |
34 | +/* puzzle magic for lart | |
35 | + * data_*_flash are def'd in flashasm.S | |
36 | + */ | |
37 | + | |
38 | +extern u32 data_from_flash(u32); | |
39 | +extern u32 data_to_flash(u32); | |
40 | + | |
41 | +#define PUZZLE_FROM_FLASH(x) (x) | |
42 | +#define PUZZLE_TO_FLASH(x) (x) | |
43 | + | |
44 | +flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; | |
45 | + | |
46 | + | |
47 | +#define CMD_READ_ARRAY 0x00FF00FF | |
48 | +#define CMD_IDENTIFY 0x00900090 | |
49 | +#define CMD_ERASE_SETUP 0x00200020 | |
50 | +#define CMD_ERASE_CONFIRM 0x00D000D0 | |
51 | +#define CMD_PROGRAM 0x00400040 | |
52 | +#define CMD_RESUME 0x00D000D0 | |
53 | +#define CMD_SUSPEND 0x00B000B0 | |
54 | +#define CMD_STATUS_READ 0x00700070 | |
55 | +#define CMD_STATUS_RESET 0x00500050 | |
56 | + | |
57 | +#define BIT_BUSY 0x00800080 | |
58 | +#define BIT_ERASE_SUSPEND 0x00400040 | |
59 | +#define BIT_ERASE_ERROR 0x00200020 | |
60 | +#define BIT_PROGRAM_ERROR 0x00100010 | |
61 | +#define BIT_VPP_RANGE_ERROR 0x00080008 | |
62 | +#define BIT_PROGRAM_SUSPEND 0x00040004 | |
63 | +#define BIT_PROTECT_ERROR 0x00020002 | |
64 | +#define BIT_UNDEFINED 0x00010001 | |
65 | + | |
66 | +#define BIT_SEQUENCE_ERROR 0x00300030 | |
67 | +#define BIT_TIMEOUT 0x80000000 | |
68 | + | |
69 | +/*----------------------------------------------------------------------- | |
70 | + */ | |
71 | + | |
72 | +ulong flash_init(void) | |
73 | +{ | |
74 | + int i, j; | |
75 | + ulong size = 0; | |
76 | + | |
77 | + for (i = 0; i < CFG_MAX_FLASH_BANKS; i++) | |
78 | + { | |
79 | + ulong flashbase = 0; | |
80 | + flash_info[i].flash_id = | |
81 | + (INTEL_MANUFACT & FLASH_VENDMASK) | | |
82 | + (INTEL_ID_28F160F3B & FLASH_TYPEMASK); | |
83 | + flash_info[i].size = FLASH_BANK_SIZE; | |
84 | + flash_info[i].sector_count = CFG_MAX_FLASH_SECT; | |
85 | + memset(flash_info[i].protect, 0, CFG_MAX_FLASH_SECT); | |
86 | + if (i == 0) | |
87 | + flashbase = PHYS_FLASH_1; | |
88 | + else | |
89 | + panic("configured to many flash banks!\n"); | |
90 | + for (j = 0; j < flash_info[i].sector_count; j++) | |
91 | + { | |
92 | + if (j <= 7) | |
93 | + { | |
94 | + flash_info[i].start[j] = flashbase + j * PARAM_SECT_SIZE; | |
95 | + } | |
96 | + else | |
97 | + { | |
98 | + flash_info[i].start[j] = flashbase + (j - 7)*MAIN_SECT_SIZE; | |
99 | + } | |
100 | + } | |
101 | + size += flash_info[i].size; | |
102 | + } | |
103 | + | |
104 | + /* Protect monitor and environment sectors | |
105 | + */ | |
106 | + flash_protect(FLAG_PROTECT_SET, | |
107 | + CFG_FLASH_BASE, | |
108 | + CFG_FLASH_BASE + _armboot_end_data - _armboot_start, | |
109 | + &flash_info[0]); | |
110 | + | |
111 | + flash_protect(FLAG_PROTECT_SET, | |
112 | + CFG_ENV_ADDR, | |
113 | + CFG_ENV_ADDR + CFG_ENV_SIZE - 1, | |
114 | + &flash_info[0]); | |
115 | + | |
116 | + return size; | |
117 | +} | |
118 | + | |
119 | +/*----------------------------------------------------------------------- | |
120 | + */ | |
121 | +void flash_print_info (flash_info_t *info) | |
122 | +{ | |
123 | + int i; | |
124 | + | |
125 | + switch (info->flash_id & FLASH_VENDMASK) | |
126 | + { | |
127 | + case (INTEL_MANUFACT & FLASH_VENDMASK): | |
128 | + printf("Intel: "); | |
129 | + break; | |
130 | + default: | |
131 | + printf("Unknown Vendor "); | |
132 | + break; | |
133 | + } | |
134 | + | |
135 | + switch (info->flash_id & FLASH_TYPEMASK) | |
136 | + { | |
137 | + case (INTEL_ID_28F160F3B & FLASH_TYPEMASK): | |
138 | + printf("2x 28F160F3B (16Mbit)\n"); | |
139 | + break; | |
140 | + default: | |
141 | + printf("Unknown Chip Type\n"); | |
142 | + goto Done; | |
143 | + break; | |
144 | + } | |
145 | + | |
146 | + printf(" Size: %ld MB in %d Sectors\n", | |
147 | + info->size >> 20, info->sector_count); | |
148 | + | |
149 | + printf(" Sector Start Addresses:"); | |
150 | + for (i = 0; i < info->sector_count; i++) | |
151 | + { | |
152 | + if ((i % 5) == 0) | |
153 | + { | |
154 | + printf ("\n "); | |
155 | + } | |
156 | + printf (" %08lX%s", info->start[i], | |
157 | + info->protect[i] ? " (RO)" : " "); | |
158 | + } | |
159 | + printf ("\n"); | |
160 | + | |
161 | +Done: | |
162 | +} | |
163 | + | |
164 | +/*----------------------------------------------------------------------- | |
165 | + */ | |
166 | + | |
167 | +int flash_error (ulong code) | |
168 | +{ | |
169 | + /* Check bit patterns */ | |
170 | + /* SR.7=0 is busy, SR.7=1 is ready */ | |
171 | + /* all other flags indicate error on 1 */ | |
172 | + /* SR.0 is undefined */ | |
173 | + /* Timeout is our faked flag */ | |
174 | + | |
175 | + /* sequence is described in Intel 290644-005 document */ | |
176 | + | |
177 | + /* check Timeout */ | |
178 | + if (code & BIT_TIMEOUT) | |
179 | + { | |
180 | + printf ("Timeout\n"); | |
181 | + return ERR_TIMOUT; | |
182 | + } | |
183 | + | |
184 | + /* check Busy, SR.7 */ | |
185 | + if (~code & BIT_BUSY) | |
186 | + { | |
187 | + printf ("Busy\n"); | |
188 | + return ERR_PROG_ERROR; | |
189 | + } | |
190 | + | |
191 | + /* check Vpp low, SR.3 */ | |
192 | + if (code & BIT_VPP_RANGE_ERROR) | |
193 | + { | |
194 | + printf ("Vpp range error\n"); | |
195 | + return ERR_PROG_ERROR; | |
196 | + } | |
197 | + | |
198 | + /* check Device Protect Error, SR.1 */ | |
199 | + if (code & BIT_PROTECT_ERROR) | |
200 | + { | |
201 | + printf ("Device protect error\n"); | |
202 | + return ERR_PROG_ERROR; | |
203 | + } | |
204 | + | |
205 | + /* check Command Seq Error, SR.4 & SR.5 */ | |
206 | + if (code & BIT_SEQUENCE_ERROR) | |
207 | + { | |
208 | + printf ("Command seqence error\n"); | |
209 | + return ERR_PROG_ERROR; | |
210 | + } | |
211 | + | |
212 | + /* check Block Erase Error, SR.5 */ | |
213 | + if (code & BIT_ERASE_ERROR) | |
214 | + { | |
215 | + printf ("Block erase error\n"); | |
216 | + return ERR_PROG_ERROR; | |
217 | + } | |
218 | + | |
219 | + /* check Program Error, SR.4 */ | |
220 | + if (code & BIT_PROGRAM_ERROR) | |
221 | + { | |
222 | + printf ("Program error\n"); | |
223 | + return ERR_PROG_ERROR; | |
224 | + } | |
225 | + | |
226 | + /* check Block Erase Suspended, SR.6 */ | |
227 | + if (code & BIT_ERASE_SUSPEND) | |
228 | + { | |
229 | + printf ("Block erase suspended\n"); | |
230 | + return ERR_PROG_ERROR; | |
231 | + } | |
232 | + | |
233 | + /* check Program Suspended, SR.2 */ | |
234 | + if (code & BIT_PROGRAM_SUSPEND) | |
235 | + { | |
236 | + printf ("Program suspended\n"); | |
237 | + return ERR_PROG_ERROR; | |
238 | + } | |
239 | + | |
240 | + /* OK, no error */ | |
241 | + return ERR_OK; | |
242 | +} | |
243 | + | |
244 | +/*----------------------------------------------------------------------- | |
245 | + */ | |
246 | + | |
247 | +int flash_erase (flash_info_t *info, int s_first, int s_last) | |
248 | +{ | |
249 | + ulong result; | |
250 | + int iflag, cflag, prot, sect; | |
251 | + int rc = ERR_OK; | |
252 | + | |
253 | + /* first look for protection bits */ | |
254 | + | |
255 | + if (info->flash_id == FLASH_UNKNOWN) | |
256 | + return ERR_UNKNOWN_FLASH_TYPE; | |
257 | + | |
258 | + if ((s_first < 0) || (s_first > s_last)) { | |
259 | + return ERR_INVAL; | |
260 | + } | |
261 | + | |
262 | + if ((info->flash_id & FLASH_VENDMASK) != | |
263 | + (INTEL_MANUFACT & FLASH_VENDMASK)) { | |
264 | + return ERR_UNKNOWN_FLASH_VENDOR; | |
265 | + } | |
266 | + | |
267 | + prot = 0; | |
268 | + for (sect=s_first; sect<=s_last; ++sect) { | |
269 | + if (info->protect[sect]) { | |
270 | + prot++; | |
271 | + } | |
272 | + } | |
273 | + if (prot) | |
274 | + return ERR_PROTECTED; | |
275 | + | |
276 | + /* | |
277 | + * Disable interrupts which might cause a timeout | |
278 | + * here. Remember that our exception vectors are | |
279 | + * at address 0 in the flash, and we don't want a | |
280 | + * (ticker) exception to happen while the flash | |
281 | + * chip is in programming mode. | |
282 | + */ | |
283 | + cflag = icache_status(); | |
284 | + icache_disable(); | |
285 | + iflag = disable_interrupts(); | |
286 | + | |
287 | + /* Start erase on unprotected sectors */ | |
288 | + for (sect = s_first; sect<=s_last && !ctrlc(); sect++) | |
289 | + { | |
290 | + printf("Erasing sector %2d ... ", sect); | |
291 | + | |
292 | + /* arm simple, non interrupt dependent timer */ | |
293 | + reset_timer_masked(); | |
294 | + | |
295 | + if (info->protect[sect] == 0) | |
296 | + { /* not protected */ | |
297 | + vu_long *addr = (vu_long *)(info->start[sect]); | |
298 | + | |
299 | + *addr = PUZZLE_TO_FLASH(CMD_STATUS_RESET); | |
300 | + *addr = PUZZLE_TO_FLASH(CMD_ERASE_SETUP); | |
301 | + *addr = PUZZLE_TO_FLASH(CMD_ERASE_CONFIRM); | |
302 | + | |
303 | + /* wait until flash is ready */ | |
304 | + do | |
305 | + { | |
306 | + /* check timeout */ | |
307 | + if (get_timer_masked() > CFG_FLASH_ERASE_TOUT) | |
308 | + { | |
309 | + *addr = PUZZLE_TO_FLASH(CMD_SUSPEND); | |
310 | + result = BIT_TIMEOUT; | |
311 | + break; | |
312 | + } | |
313 | + | |
314 | + result = PUZZLE_FROM_FLASH(*addr); | |
315 | + } while (~result & BIT_BUSY); | |
316 | + | |
317 | + *addr = PUZZLE_TO_FLASH(CMD_READ_ARRAY); | |
318 | + | |
319 | + if ((rc = flash_error(result)) != ERR_OK) | |
320 | + goto outahere; | |
321 | + | |
322 | + printf("ok.\n"); | |
323 | + } | |
324 | + else /* it was protected */ | |
325 | + { | |
326 | + printf("protected!\n"); | |
327 | + } | |
328 | + } | |
329 | + | |
330 | + if (ctrlc()) | |
331 | + printf("User Interrupt!\n"); | |
332 | + | |
333 | +outahere: | |
334 | + /* allow flash to settle - wait 10 ms */ | |
335 | + udelay_masked(10000); | |
336 | + | |
337 | + if (iflag) | |
338 | + enable_interrupts(); | |
339 | + | |
340 | + if (cflag) | |
341 | + icache_enable(); | |
342 | + | |
343 | + return rc; | |
344 | +} | |
345 | + | |
346 | +/*----------------------------------------------------------------------- | |
347 | + * Copy memory to flash | |
348 | + */ | |
349 | + | |
350 | +volatile static int write_word (flash_info_t *info, ulong dest, ulong data) | |
351 | +{ | |
352 | + vu_long *addr = (vu_long *)dest; | |
353 | + ulong result; | |
354 | + int rc = ERR_OK; | |
355 | + int cflag, iflag; | |
356 | + | |
357 | + /* Check if Flash is (sufficiently) erased | |
358 | + */ | |
359 | + result = PUZZLE_FROM_FLASH(*addr); | |
360 | + if ((result & data) != data) | |
361 | + return ERR_NOT_ERASED; | |
362 | + | |
363 | + /* | |
364 | + * Disable interrupts which might cause a timeout | |
365 | + * here. Remember that our exception vectors are | |
366 | + * at address 0 in the flash, and we don't want a | |
367 | + * (ticker) exception to happen while the flash | |
368 | + * chip is in programming mode. | |
369 | + */ | |
370 | + cflag = icache_status(); | |
371 | + icache_disable(); | |
372 | + iflag = disable_interrupts(); | |
373 | + | |
374 | + *addr = PUZZLE_TO_FLASH(CMD_STATUS_RESET); | |
375 | + *addr = PUZZLE_TO_FLASH(CMD_PROGRAM); | |
376 | + *addr = data; | |
377 | + | |
378 | + /* arm simple, non interrupt dependent timer */ | |
379 | + reset_timer_masked(); | |
380 | + | |
381 | + /* wait until flash is ready */ | |
382 | + do | |
383 | + { | |
384 | + /* check timeout */ | |
385 | + if (get_timer_masked() > CFG_FLASH_ERASE_TOUT) | |
386 | + { | |
387 | + *addr = PUZZLE_TO_FLASH(CMD_SUSPEND); | |
388 | + result = BIT_TIMEOUT; | |
389 | + break; | |
390 | + } | |
391 | + | |
392 | + result = PUZZLE_FROM_FLASH(*addr); | |
393 | + } while (~result & BIT_BUSY); | |
394 | + | |
395 | + *addr = PUZZLE_TO_FLASH(CMD_READ_ARRAY); | |
396 | + | |
397 | + rc = flash_error(result); | |
398 | + | |
399 | + if (iflag) | |
400 | + enable_interrupts(); | |
401 | + | |
402 | + if (cflag) | |
403 | + icache_enable(); | |
404 | + | |
405 | + return rc; | |
406 | +} | |
407 | + | |
408 | +/*----------------------------------------------------------------------- | |
409 | + * Copy memory to flash. | |
410 | + */ | |
411 | + | |
412 | +int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt) | |
413 | +{ | |
414 | + ulong cp, wp, data; | |
415 | + int l; | |
416 | + int i, rc; | |
417 | + | |
418 | + wp = (addr & ~3); /* get lower word aligned address */ | |
419 | + | |
420 | + /* | |
421 | + * handle unaligned start bytes | |
422 | + */ | |
423 | + if ((l = addr - wp) != 0) { | |
424 | + data = 0; | |
425 | + for (i=0, cp=wp; i<l; ++i, ++cp) { | |
426 | + data = (data >> 8) | (*(uchar *)cp << 24); | |
427 | + } | |
428 | + for (; i<4 && cnt>0; ++i) { | |
429 | + data = (data >> 8) | (*src++ << 24); | |
430 | + --cnt; | |
431 | + ++cp; | |
432 | + } | |
433 | + for (; cnt==0 && i<4; ++i, ++cp) { | |
434 | + data = (data >> 8) | (*(uchar *)cp << 24); | |
435 | + } | |
436 | + | |
437 | + if ((rc = write_word(info, wp, data)) != 0) { | |
438 | + return (rc); | |
439 | + } | |
440 | + wp += 4; | |
441 | + } | |
442 | + | |
443 | + /* | |
444 | + * handle word aligned part | |
445 | + */ | |
446 | + while (cnt >= 4) { | |
447 | + data = *((vu_long*)src); | |
448 | + if ((rc = write_word(info, wp, data)) != 0) { | |
449 | + return (rc); | |
450 | + } | |
451 | + src += 4; | |
452 | + wp += 4; | |
453 | + cnt -= 4; | |
454 | + } | |
455 | + | |
456 | + if (cnt == 0) { | |
457 | + return ERR_OK; | |
458 | + } | |
459 | + | |
460 | + /* | |
461 | + * handle unaligned tail bytes | |
462 | + */ | |
463 | + data = 0; | |
464 | + for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) { | |
465 | + data = (data >> 8) | (*src++ << 24); | |
466 | + --cnt; | |
467 | + } | |
468 | + for (; i<4; ++i, ++cp) { | |
469 | + data = (data >> 8) | (*(uchar *)cp << 24); | |
470 | + } | |
471 | + | |
472 | + return write_word(info, wp, data); | |
473 | +} |
@@ -0,0 +1,473 @@ | ||
1 | +/* | |
2 | + * (C) Copyright 2002 | |
3 | + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> | |
4 | + * Marius Groeger <mgroeger@sysgo.de> | |
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 | +#include <common.h> | |
26 | + | |
27 | +ulong myflush(void); | |
28 | + | |
29 | + | |
30 | +#define FLASH_BANK_SIZE 0x800000 | |
31 | +#define MAIN_SECT_SIZE 0x20000 | |
32 | +#define PARAM_SECT_SIZE 0x4000 | |
33 | + | |
34 | +/* puzzle magic for lart | |
35 | + * data_*_flash are def'd in flashasm.S | |
36 | + */ | |
37 | + | |
38 | +extern u32 data_from_flash(u32); | |
39 | +extern u32 data_to_flash(u32); | |
40 | + | |
41 | +#define PUZZLE_FROM_FLASH(x) data_from_flash((x)) | |
42 | +#define PUZZLE_TO_FLASH(x) data_to_flash((x)) | |
43 | + | |
44 | +flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; | |
45 | + | |
46 | + | |
47 | +#define CMD_READ_ARRAY 0x00FF00FF | |
48 | +#define CMD_IDENTIFY 0x00900090 | |
49 | +#define CMD_ERASE_SETUP 0x00200020 | |
50 | +#define CMD_ERASE_CONFIRM 0x00D000D0 | |
51 | +#define CMD_PROGRAM 0x00400040 | |
52 | +#define CMD_RESUME 0x00D000D0 | |
53 | +#define CMD_SUSPEND 0x00B000B0 | |
54 | +#define CMD_STATUS_READ 0x00700070 | |
55 | +#define CMD_STATUS_RESET 0x00500050 | |
56 | + | |
57 | +#define BIT_BUSY 0x00800080 | |
58 | +#define BIT_ERASE_SUSPEND 0x00400040 | |
59 | +#define BIT_ERASE_ERROR 0x00200020 | |
60 | +#define BIT_PROGRAM_ERROR 0x00100010 | |
61 | +#define BIT_VPP_RANGE_ERROR 0x00080008 | |
62 | +#define BIT_PROGRAM_SUSPEND 0x00040004 | |
63 | +#define BIT_PROTECT_ERROR 0x00020002 | |
64 | +#define BIT_UNDEFINED 0x00010001 | |
65 | + | |
66 | +#define BIT_SEQUENCE_ERROR 0x00300030 | |
67 | +#define BIT_TIMEOUT 0x80000000 | |
68 | + | |
69 | +/*----------------------------------------------------------------------- | |
70 | + */ | |
71 | + | |
72 | +ulong flash_init(void) | |
73 | +{ | |
74 | + int i, j; | |
75 | + ulong size = 0; | |
76 | + | |
77 | + for (i = 0; i < CFG_MAX_FLASH_BANKS; i++) | |
78 | + { | |
79 | + ulong flashbase = 0; | |
80 | + flash_info[i].flash_id = | |
81 | + (INTEL_MANUFACT & FLASH_VENDMASK) | | |
82 | + (INTEL_ID_28F160F3B & FLASH_TYPEMASK); | |
83 | + flash_info[i].size = FLASH_BANK_SIZE; | |
84 | + flash_info[i].sector_count = CFG_MAX_FLASH_SECT; | |
85 | + memset(flash_info[i].protect, 0, CFG_MAX_FLASH_SECT); | |
86 | + if (i == 0) | |
87 | + flashbase = PHYS_FLASH_1; | |
88 | + else | |
89 | + panic("configured to many flash banks!\n"); | |
90 | + for (j = 0; j < flash_info[i].sector_count; j++) | |
91 | + { | |
92 | + if (j <= 7) | |
93 | + { | |
94 | + flash_info[i].start[j] = flashbase + j * PARAM_SECT_SIZE; | |
95 | + } | |
96 | + else | |
97 | + { | |
98 | + flash_info[i].start[j] = flashbase + (j - 7)*MAIN_SECT_SIZE; | |
99 | + } | |
100 | + } | |
101 | + size += flash_info[i].size; | |
102 | + } | |
103 | + | |
104 | + /* Protect monitor and environment sectors | |
105 | + */ | |
106 | + flash_protect(FLAG_PROTECT_SET, | |
107 | + CFG_FLASH_BASE, | |
108 | + CFG_FLASH_BASE + _armboot_end_data - _armboot_start, | |
109 | + &flash_info[0]); | |
110 | + | |
111 | + flash_protect(FLAG_PROTECT_SET, | |
112 | + CFG_ENV_ADDR, | |
113 | + CFG_ENV_ADDR + CFG_ENV_SIZE - 1, | |
114 | + &flash_info[0]); | |
115 | + | |
116 | + return size; | |
117 | +} | |
118 | + | |
119 | +/*----------------------------------------------------------------------- | |
120 | + */ | |
121 | +void flash_print_info (flash_info_t *info) | |
122 | +{ | |
123 | + int i; | |
124 | + | |
125 | + switch (info->flash_id & FLASH_VENDMASK) | |
126 | + { | |
127 | + case (INTEL_MANUFACT & FLASH_VENDMASK): | |
128 | + printf("Intel: "); | |
129 | + break; | |
130 | + default: | |
131 | + printf("Unknown Vendor "); | |
132 | + break; | |
133 | + } | |
134 | + | |
135 | + switch (info->flash_id & FLASH_TYPEMASK) | |
136 | + { | |
137 | + case (INTEL_ID_28F160F3B & FLASH_TYPEMASK): | |
138 | + printf("2x 28F160F3B (16Mbit)\n"); | |
139 | + break; | |
140 | + default: | |
141 | + printf("Unknown Chip Type\n"); | |
142 | + goto Done; | |
143 | + break; | |
144 | + } | |
145 | + | |
146 | + printf(" Size: %ld MB in %d Sectors\n", | |
147 | + info->size >> 20, info->sector_count); | |
148 | + | |
149 | + printf(" Sector Start Addresses:"); | |
150 | + for (i = 0; i < info->sector_count; i++) | |
151 | + { | |
152 | + if ((i % 5) == 0) | |
153 | + { | |
154 | + printf ("\n "); | |
155 | + } | |
156 | + printf (" %08lX%s", info->start[i], | |
157 | + info->protect[i] ? " (RO)" : " "); | |
158 | + } | |
159 | + printf ("\n"); | |
160 | + | |
161 | +Done: | |
162 | +} | |
163 | + | |
164 | +/*----------------------------------------------------------------------- | |
165 | + */ | |
166 | + | |
167 | +int flash_error (ulong code) | |
168 | +{ | |
169 | + /* Check bit patterns */ | |
170 | + /* SR.7=0 is busy, SR.7=1 is ready */ | |
171 | + /* all other flags indicate error on 1 */ | |
172 | + /* SR.0 is undefined */ | |
173 | + /* Timeout is our faked flag */ | |
174 | + | |
175 | + /* sequence is described in Intel 290644-005 document */ | |
176 | + | |
177 | + /* check Timeout */ | |
178 | + if (code & BIT_TIMEOUT) | |
179 | + { | |
180 | + printf ("Timeout\n"); | |
181 | + return ERR_TIMOUT; | |
182 | + } | |
183 | + | |
184 | + /* check Busy, SR.7 */ | |
185 | + if (~code & BIT_BUSY) | |
186 | + { | |
187 | + printf ("Busy\n"); | |
188 | + return ERR_PROG_ERROR; | |
189 | + } | |
190 | + | |
191 | + /* check Vpp low, SR.3 */ | |
192 | + if (code & BIT_VPP_RANGE_ERROR) | |
193 | + { | |
194 | + printf ("Vpp range error\n"); | |
195 | + return ERR_PROG_ERROR; | |
196 | + } | |
197 | + | |
198 | + /* check Device Protect Error, SR.1 */ | |
199 | + if (code & BIT_PROTECT_ERROR) | |
200 | + { | |
201 | + printf ("Device protect error\n"); | |
202 | + return ERR_PROG_ERROR; | |
203 | + } | |
204 | + | |
205 | + /* check Command Seq Error, SR.4 & SR.5 */ | |
206 | + if (code & BIT_SEQUENCE_ERROR) | |
207 | + { | |
208 | + printf ("Command seqence error\n"); | |
209 | + return ERR_PROG_ERROR; | |
210 | + } | |
211 | + | |
212 | + /* check Block Erase Error, SR.5 */ | |
213 | + if (code & BIT_ERASE_ERROR) | |
214 | + { | |
215 | + printf ("Block erase error\n"); | |
216 | + return ERR_PROG_ERROR; | |
217 | + } | |
218 | + | |
219 | + /* check Program Error, SR.4 */ | |
220 | + if (code & BIT_PROGRAM_ERROR) | |
221 | + { | |
222 | + printf ("Program error\n"); | |
223 | + return ERR_PROG_ERROR; | |
224 | + } | |
225 | + | |
226 | + /* check Block Erase Suspended, SR.6 */ | |
227 | + if (code & BIT_ERASE_SUSPEND) | |
228 | + { | |
229 | + printf ("Block erase suspended\n"); | |
230 | + return ERR_PROG_ERROR; | |
231 | + } | |
232 | + | |
233 | + /* check Program Suspended, SR.2 */ | |
234 | + if (code & BIT_PROGRAM_SUSPEND) | |
235 | + { | |
236 | + printf ("Program suspended\n"); | |
237 | + return ERR_PROG_ERROR; | |
238 | + } | |
239 | + | |
240 | + /* OK, no error */ | |
241 | + return ERR_OK; | |
242 | +} | |
243 | + | |
244 | +/*----------------------------------------------------------------------- | |
245 | + */ | |
246 | + | |
247 | +int flash_erase (flash_info_t *info, int s_first, int s_last) | |
248 | +{ | |
249 | + ulong result; | |
250 | + int iflag, cflag, prot, sect; | |
251 | + int rc = ERR_OK; | |
252 | + | |
253 | + /* first look for protection bits */ | |
254 | + | |
255 | + if (info->flash_id == FLASH_UNKNOWN) | |
256 | + return ERR_UNKNOWN_FLASH_TYPE; | |
257 | + | |
258 | + if ((s_first < 0) || (s_first > s_last)) { | |
259 | + return ERR_INVAL; | |
260 | + } | |
261 | + | |
262 | + if ((info->flash_id & FLASH_VENDMASK) != | |
263 | + (INTEL_MANUFACT & FLASH_VENDMASK)) { | |
264 | + return ERR_UNKNOWN_FLASH_VENDOR; | |
265 | + } | |
266 | + | |
267 | + prot = 0; | |
268 | + for (sect=s_first; sect<=s_last; ++sect) { | |
269 | + if (info->protect[sect]) { | |
270 | + prot++; | |
271 | + } | |
272 | + } | |
273 | + if (prot) | |
274 | + return ERR_PROTECTED; | |
275 | + | |
276 | + /* | |
277 | + * Disable interrupts which might cause a timeout | |
278 | + * here. Remember that our exception vectors are | |
279 | + * at address 0 in the flash, and we don't want a | |
280 | + * (ticker) exception to happen while the flash | |
281 | + * chip is in programming mode. | |
282 | + */ | |
283 | + cflag = icache_status(); | |
284 | + icache_disable(); | |
285 | + iflag = disable_interrupts(); | |
286 | + | |
287 | + /* Start erase on unprotected sectors */ | |
288 | + for (sect = s_first; sect<=s_last && !ctrlc(); sect++) | |
289 | + { | |
290 | + printf("Erasing sector %2d ... ", sect); | |
291 | + | |
292 | + /* arm simple, non interrupt dependent timer */ | |
293 | + reset_timer_masked(); | |
294 | + | |
295 | + if (info->protect[sect] == 0) | |
296 | + { /* not protected */ | |
297 | + vu_long *addr = (vu_long *)(info->start[sect]); | |
298 | + | |
299 | + *addr = PUZZLE_TO_FLASH(CMD_STATUS_RESET); | |
300 | + *addr = PUZZLE_TO_FLASH(CMD_ERASE_SETUP); | |
301 | + *addr = PUZZLE_TO_FLASH(CMD_ERASE_CONFIRM); | |
302 | + | |
303 | + /* wait until flash is ready */ | |
304 | + do | |
305 | + { | |
306 | + /* check timeout */ | |
307 | + if (get_timer_masked() > CFG_FLASH_ERASE_TOUT) | |
308 | + { | |
309 | + *addr = PUZZLE_TO_FLASH(CMD_SUSPEND); | |
310 | + result = BIT_TIMEOUT; | |
311 | + break; | |
312 | + } | |
313 | + | |
314 | + result = PUZZLE_FROM_FLASH(*addr); | |
315 | + } while (~result & BIT_BUSY); | |
316 | + | |
317 | + *addr = PUZZLE_TO_FLASH(CMD_READ_ARRAY); | |
318 | + | |
319 | + if ((rc = flash_error(result)) != ERR_OK) | |
320 | + goto outahere; | |
321 | + | |
322 | + printf("ok.\n"); | |
323 | + } | |
324 | + else /* it was protected */ | |
325 | + { | |
326 | + printf("protected!\n"); | |
327 | + } | |
328 | + } | |
329 | + | |
330 | + if (ctrlc()) | |
331 | + printf("User Interrupt!\n"); | |
332 | + | |
333 | +outahere: | |
334 | + /* allow flash to settle - wait 10 ms */ | |
335 | + udelay_masked(10000); | |
336 | + | |
337 | + if (iflag) | |
338 | + enable_interrupts(); | |
339 | + | |
340 | + if (cflag) | |
341 | + icache_enable(); | |
342 | + | |
343 | + return rc; | |
344 | +} | |
345 | + | |
346 | +/*----------------------------------------------------------------------- | |
347 | + * Copy memory to flash | |
348 | + */ | |
349 | + | |
350 | +volatile static int write_word (flash_info_t *info, ulong dest, ulong data) | |
351 | +{ | |
352 | + vu_long *addr = (vu_long *)dest; | |
353 | + ulong result; | |
354 | + int rc = ERR_OK; | |
355 | + int cflag, iflag; | |
356 | + | |
357 | + /* Check if Flash is (sufficiently) erased | |
358 | + */ | |
359 | + result = PUZZLE_FROM_FLASH(*addr); | |
360 | + if ((result & data) != data) | |
361 | + return ERR_NOT_ERASED; | |
362 | + | |
363 | + /* | |
364 | + * Disable interrupts which might cause a timeout | |
365 | + * here. Remember that our exception vectors are | |
366 | + * at address 0 in the flash, and we don't want a | |
367 | + * (ticker) exception to happen while the flash | |
368 | + * chip is in programming mode. | |
369 | + */ | |
370 | + cflag = icache_status(); | |
371 | + icache_disable(); | |
372 | + iflag = disable_interrupts(); | |
373 | + | |
374 | + *addr = PUZZLE_TO_FLASH(CMD_STATUS_RESET); | |
375 | + *addr = PUZZLE_TO_FLASH(CMD_PROGRAM); | |
376 | + *addr = data; | |
377 | + | |
378 | + /* arm simple, non interrupt dependent timer */ | |
379 | + reset_timer_masked(); | |
380 | + | |
381 | + /* wait until flash is ready */ | |
382 | + do | |
383 | + { | |
384 | + /* check timeout */ | |
385 | + if (get_timer_masked() > CFG_FLASH_ERASE_TOUT) | |
386 | + { | |
387 | + *addr = PUZZLE_TO_FLASH(CMD_SUSPEND); | |
388 | + result = BIT_TIMEOUT; | |
389 | + break; | |
390 | + } | |
391 | + | |
392 | + result = PUZZLE_FROM_FLASH(*addr); | |
393 | + } while (~result & BIT_BUSY); | |
394 | + | |
395 | + *addr = PUZZLE_TO_FLASH(CMD_READ_ARRAY); | |
396 | + | |
397 | + rc = flash_error(result); | |
398 | + | |
399 | + if (iflag) | |
400 | + enable_interrupts(); | |
401 | + | |
402 | + if (cflag) | |
403 | + icache_enable(); | |
404 | + | |
405 | + return rc; | |
406 | +} | |
407 | + | |
408 | +/*----------------------------------------------------------------------- | |
409 | + * Copy memory to flash. | |
410 | + */ | |
411 | + | |
412 | +int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt) | |
413 | +{ | |
414 | + ulong cp, wp, data; | |
415 | + int l; | |
416 | + int i, rc; | |
417 | + | |
418 | + wp = (addr & ~3); /* get lower word aligned address */ | |
419 | + | |
420 | + /* | |
421 | + * handle unaligned start bytes | |
422 | + */ | |
423 | + if ((l = addr - wp) != 0) { | |
424 | + data = 0; | |
425 | + for (i=0, cp=wp; i<l; ++i, ++cp) { | |
426 | + data = (data >> 8) | (*(uchar *)cp << 24); | |
427 | + } | |
428 | + for (; i<4 && cnt>0; ++i) { | |
429 | + data = (data >> 8) | (*src++ << 24); | |
430 | + --cnt; | |
431 | + ++cp; | |
432 | + } | |
433 | + for (; cnt==0 && i<4; ++i, ++cp) { | |
434 | + data = (data >> 8) | (*(uchar *)cp << 24); | |
435 | + } | |
436 | + | |
437 | + if ((rc = write_word(info, wp, data)) != 0) { | |
438 | + return (rc); | |
439 | + } | |
440 | + wp += 4; | |
441 | + } | |
442 | + | |
443 | + /* | |
444 | + * handle word aligned part | |
445 | + */ | |
446 | + while (cnt >= 4) { | |
447 | + data = *((vu_long*)src); | |
448 | + if ((rc = write_word(info, wp, data)) != 0) { | |
449 | + return (rc); | |
450 | + } | |
451 | + src += 4; | |
452 | + wp += 4; | |
453 | + cnt -= 4; | |
454 | + } | |
455 | + | |
456 | + if (cnt == 0) { | |
457 | + return ERR_OK; | |
458 | + } | |
459 | + | |
460 | + /* | |
461 | + * handle unaligned tail bytes | |
462 | + */ | |
463 | + data = 0; | |
464 | + for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) { | |
465 | + data = (data >> 8) | (*src++ << 24); | |
466 | + --cnt; | |
467 | + } | |
468 | + for (; i<4; ++i, ++cp) { | |
469 | + data = (data >> 8) | (*(uchar *)cp << 24); | |
470 | + } | |
471 | + | |
472 | + return write_word(info, wp, data); | |
473 | +} |
@@ -0,0 +1,363 @@ | ||
1 | +/* | |
2 | + * (C) Copyright 2002 | |
3 | + * Kyle Harris, Nexus Technologies, Inc. kharris@nexus-tech.net | |
4 | + * | |
5 | + * (C) Copyright 2002 | |
6 | + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> | |
7 | + * Marius Groeger <mgroeger@sysgo.de> | |
8 | + * | |
9 | + * See file CREDITS for list of people who contributed to this | |
10 | + * project. | |
11 | + * | |
12 | + * This program is free software; you can redistribute it and/or | |
13 | + * modify it under the terms of the GNU General Public License as | |
14 | + * published by the Free Software Foundation; either version 2 of | |
15 | + * the License, or (at your option) any later version. | |
16 | + * | |
17 | + * This program is distributed in the hope that it will be useful, | |
18 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
19 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
20 | + * GNU General Public License for more details. | |
21 | + * | |
22 | + * You should have received a copy of the GNU General Public License | |
23 | + * along with this program; if not, write to the Free Software | |
24 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
25 | + * MA 02111-1307 USA | |
26 | + */ | |
27 | + | |
28 | +#include <common.h> | |
29 | + | |
30 | +#define FLASH_BANK_SIZE 0x2000000 | |
31 | +#define MAIN_SECT_SIZE 0x40000 /* 2x16 = 256k per sector */ | |
32 | + | |
33 | +flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; | |
34 | + | |
35 | + | |
36 | +/*----------------------------------------------------------------------- | |
37 | + */ | |
38 | + | |
39 | +ulong flash_init(void) | |
40 | +{ | |
41 | + int i, j; | |
42 | + ulong size = 0; | |
43 | + | |
44 | + for (i = 0; i < CFG_MAX_FLASH_BANKS; i++) | |
45 | + { | |
46 | + ulong flashbase = 0; | |
47 | + flash_info[i].flash_id = | |
48 | + (INTEL_MANUFACT & FLASH_VENDMASK) | | |
49 | + (INTEL_ID_28F128J3 & FLASH_TYPEMASK); | |
50 | + flash_info[i].size = FLASH_BANK_SIZE; | |
51 | + flash_info[i].sector_count = CFG_MAX_FLASH_SECT; | |
52 | + memset(flash_info[i].protect, 0, CFG_MAX_FLASH_SECT); | |
53 | + switch (i) | |
54 | + { | |
55 | + case 0: | |
56 | + flashbase = PHYS_FLASH_1; | |
57 | + break; | |
58 | + case 1: | |
59 | + flashbase = PHYS_FLASH_2; | |
60 | + break; | |
61 | + default: | |
62 | + panic("configured to many flash banks!\n"); | |
63 | + break; | |
64 | + } | |
65 | + for (j = 0; j < flash_info[i].sector_count; j++) | |
66 | + { | |
67 | + flash_info[i].start[j] = flashbase + j*MAIN_SECT_SIZE; | |
68 | + } | |
69 | + size += flash_info[i].size; | |
70 | + } | |
71 | + | |
72 | + /* Protect monitor and environment sectors | |
73 | + */ | |
74 | + flash_protect(FLAG_PROTECT_SET, | |
75 | + CFG_FLASH_BASE, | |
76 | + CFG_FLASH_BASE + _armboot_end_data - _armboot_start, | |
77 | + &flash_info[0]); | |
78 | + | |
79 | + flash_protect(FLAG_PROTECT_SET, | |
80 | + CFG_ENV_ADDR, | |
81 | + CFG_ENV_ADDR + CFG_ENV_SIZE - 1, | |
82 | + &flash_info[0]); | |
83 | + | |
84 | + return size; | |
85 | +} | |
86 | + | |
87 | +/*----------------------------------------------------------------------- | |
88 | + */ | |
89 | +void flash_print_info (flash_info_t *info) | |
90 | +{ | |
91 | + int i, j; | |
92 | + | |
93 | + for (j=0; j<CFG_MAX_FLASH_BANKS; j++) | |
94 | + { | |
95 | + switch (info->flash_id & FLASH_VENDMASK) | |
96 | + { | |
97 | + case (INTEL_MANUFACT & FLASH_VENDMASK): | |
98 | + printf("Intel: "); | |
99 | + break; | |
100 | + default: | |
101 | + printf("Unknown Vendor "); | |
102 | + break; | |
103 | + } | |
104 | + | |
105 | + switch (info->flash_id & FLASH_TYPEMASK) | |
106 | + { | |
107 | + case (INTEL_ID_28F128J3 & FLASH_TYPEMASK): | |
108 | + printf("28F128J3 (128Mbit)\n"); | |
109 | + break; | |
110 | + default: | |
111 | + printf("Unknown Chip Type\n"); | |
112 | + goto Done; | |
113 | + break; | |
114 | + } | |
115 | + | |
116 | + printf(" Size: %ld MB in %d Sectors\n", | |
117 | + info->size >> 20, info->sector_count); | |
118 | + | |
119 | + printf(" Sector Start Addresses:"); | |
120 | + for (i = 0; i < info->sector_count; i++) | |
121 | + { | |
122 | + if ((i % 5) == 0) | |
123 | + { | |
124 | + printf ("\n "); | |
125 | + } | |
126 | + printf (" %08lX%s", info->start[i], | |
127 | + info->protect[i] ? " (RO)" : " "); | |
128 | + } | |
129 | + printf ("\n"); | |
130 | + info++; | |
131 | + } | |
132 | + | |
133 | +Done: | |
134 | +} | |
135 | + | |
136 | +/*----------------------------------------------------------------------- | |
137 | + */ | |
138 | + | |
139 | +int flash_erase (flash_info_t *info, int s_first, int s_last) | |
140 | +{ | |
141 | + int flag, prot, sect; | |
142 | + int rc = ERR_OK; | |
143 | + | |
144 | + if (info->flash_id == FLASH_UNKNOWN) | |
145 | + return ERR_UNKNOWN_FLASH_TYPE; | |
146 | + | |
147 | + if ((s_first < 0) || (s_first > s_last)) { | |
148 | + return ERR_INVAL; | |
149 | + } | |
150 | + | |
151 | + if ((info->flash_id & FLASH_VENDMASK) != | |
152 | + (INTEL_MANUFACT & FLASH_VENDMASK)) { | |
153 | + return ERR_UNKNOWN_FLASH_VENDOR; | |
154 | + } | |
155 | + | |
156 | + prot = 0; | |
157 | + for (sect=s_first; sect<=s_last; ++sect) { | |
158 | + if (info->protect[sect]) { | |
159 | + prot++; | |
160 | + } | |
161 | + } | |
162 | + if (prot) | |
163 | + return ERR_PROTECTED; | |
164 | + | |
165 | + /* | |
166 | + * Disable interrupts which might cause a timeout | |
167 | + * here. Remember that our exception vectors are | |
168 | + * at address 0 in the flash, and we don't want a | |
169 | + * (ticker) exception to happen while the flash | |
170 | + * chip is in programming mode. | |
171 | + */ | |
172 | + flag = disable_interrupts(); | |
173 | + | |
174 | + /* Start erase on unprotected sectors */ | |
175 | + for (sect = s_first; sect<=s_last && !ctrlc(); sect++) { | |
176 | + | |
177 | + printf("Erasing sector %2d ... ", sect); | |
178 | + | |
179 | + /* arm simple, non interrupt dependent timer */ | |
180 | + reset_timer_masked(); | |
181 | + | |
182 | + if (info->protect[sect] == 0) { /* not protected */ | |
183 | + vu_short *addr = (vu_short *)(info->start[sect]); | |
184 | + | |
185 | + *addr = 0x20; /* erase setup */ | |
186 | + *addr = 0xD0; /* erase confirm */ | |
187 | + | |
188 | + while ((*addr & 0x80) != 0x80) { | |
189 | + if (get_timer_masked() > CFG_FLASH_ERASE_TOUT) { | |
190 | + *addr = 0xB0; /* suspend erase */ | |
191 | + *addr = 0xFF; /* reset to read mode */ | |
192 | + rc = ERR_TIMOUT; | |
193 | + goto outahere; | |
194 | + } | |
195 | + } | |
196 | + | |
197 | + /* clear status register command */ | |
198 | + *addr = 0x50; | |
199 | + /* reset to read mode */ | |
200 | + *addr = 0xFF; | |
201 | + } | |
202 | + printf("ok.\n"); | |
203 | + } | |
204 | + if (ctrlc()) | |
205 | + printf("User Interrupt!\n"); | |
206 | + | |
207 | +outahere: | |
208 | + | |
209 | + /* allow flash to settle - wait 10 ms */ | |
210 | + udelay_masked(10000); | |
211 | + | |
212 | + if (flag) | |
213 | + enable_interrupts(); | |
214 | + | |
215 | + return rc; | |
216 | +} | |
217 | + | |
218 | +/*----------------------------------------------------------------------- | |
219 | + * Copy memory to flash | |
220 | + */ | |
221 | + | |
222 | +static int write_word (flash_info_t *info, ulong dest, ushort data) | |
223 | +{ | |
224 | + vu_short *addr = (vu_short *)dest, val; | |
225 | + int rc = ERR_OK; | |
226 | + int flag; | |
227 | + | |
228 | + /* Check if Flash is (sufficiently) erased | |
229 | + */ | |
230 | + if ((*addr & data) != data) | |
231 | + return ERR_NOT_ERASED; | |
232 | + | |
233 | + /* | |
234 | + * Disable interrupts which might cause a timeout | |
235 | + * here. Remember that our exception vectors are | |
236 | + * at address 0 in the flash, and we don't want a | |
237 | + * (ticker) exception to happen while the flash | |
238 | + * chip is in programming mode. | |
239 | + */ | |
240 | + flag = disable_interrupts(); | |
241 | + | |
242 | + /* clear status register command */ | |
243 | + *addr = 0x50; | |
244 | + | |
245 | + /* program set-up command */ | |
246 | + *addr = 0x40; | |
247 | + | |
248 | + /* latch address/data */ | |
249 | + *addr = data; | |
250 | + | |
251 | + /* arm simple, non interrupt dependent timer */ | |
252 | + reset_timer_masked(); | |
253 | + | |
254 | + /* wait while polling the status register */ | |
255 | + while(((val = *addr) & 0x80) != 0x80) | |
256 | + { | |
257 | + if (get_timer_masked() > CFG_FLASH_WRITE_TOUT) { | |
258 | + rc = ERR_TIMOUT; | |
259 | + /* suspend program command */ | |
260 | + *addr = 0xB0; | |
261 | + goto outahere; | |
262 | + } | |
263 | + } | |
264 | + | |
265 | + if(val & 0x1A) { /* check for error */ | |
266 | + printf("\nFlash write error %02x at address %08lx\n", | |
267 | + (int)val, (unsigned long)dest); | |
268 | + if(val & (1<<3)) { | |
269 | + printf("Voltage range error.\n"); | |
270 | + rc = ERR_PROG_ERROR; | |
271 | + goto outahere; | |
272 | + } | |
273 | + if(val & (1<<1)) { | |
274 | + printf("Device protect error.\n"); | |
275 | + rc = ERR_PROTECTED; | |
276 | + goto outahere; | |
277 | + } | |
278 | + if(val & (1<<4)) { | |
279 | + printf("Programming error.\n"); | |
280 | + rc = ERR_PROG_ERROR; | |
281 | + goto outahere; | |
282 | + } | |
283 | + rc = ERR_PROG_ERROR; | |
284 | + goto outahere; | |
285 | + } | |
286 | + | |
287 | +outahere: | |
288 | + /* read array command */ | |
289 | + *addr = 0xFF; | |
290 | + | |
291 | + if (flag) | |
292 | + enable_interrupts(); | |
293 | + | |
294 | + return rc; | |
295 | +} | |
296 | + | |
297 | +/*----------------------------------------------------------------------- | |
298 | + * Copy memory to flash. | |
299 | + */ | |
300 | + | |
301 | +int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt) | |
302 | +{ | |
303 | + ulong cp, wp; | |
304 | + ushort data; | |
305 | + int l; | |
306 | + int i, rc; | |
307 | + | |
308 | + wp = (addr & ~1); /* get lower word aligned address */ | |
309 | + | |
310 | + /* | |
311 | + * handle unaligned start bytes | |
312 | + */ | |
313 | + if ((l = addr - wp) != 0) { | |
314 | + data = 0; | |
315 | + for (i=0, cp=wp; i<l; ++i, ++cp) { | |
316 | + data = (data >> 8) | (*(uchar *)cp << 8); | |
317 | + } | |
318 | + for (; i<2 && cnt>0; ++i) { | |
319 | + data = (data >> 8) | (*src++ << 8); | |
320 | + --cnt; | |
321 | + ++cp; | |
322 | + } | |
323 | + for (; cnt==0 && i<2; ++i, ++cp) { | |
324 | + data = (data >> 8) | (*(uchar *)cp << 8); | |
325 | + } | |
326 | + | |
327 | + if ((rc = write_word(info, wp, data)) != 0) { | |
328 | + return (rc); | |
329 | + } | |
330 | + wp += 2; | |
331 | + } | |
332 | + | |
333 | + /* | |
334 | + * handle word aligned part | |
335 | + */ | |
336 | + while (cnt >= 2) { | |
337 | + data = *((vu_short*)src); | |
338 | + if ((rc = write_word(info, wp, data)) != 0) { | |
339 | + return (rc); | |
340 | + } | |
341 | + src += 2; | |
342 | + wp += 2; | |
343 | + cnt -= 2; | |
344 | + } | |
345 | + | |
346 | + if (cnt == 0) { | |
347 | + return ERR_OK; | |
348 | + } | |
349 | + | |
350 | + /* | |
351 | + * handle unaligned tail bytes | |
352 | + */ | |
353 | + data = 0; | |
354 | + for (i=0, cp=wp; i<2 && cnt>0; ++i, ++cp) { | |
355 | + data = (data >> 8) | (*src++ << 8); | |
356 | + --cnt; | |
357 | + } | |
358 | + for (; i<2; ++i, ++cp) { | |
359 | + data = (data >> 8) | (*(uchar *)cp << 8); | |
360 | + } | |
361 | + | |
362 | + return write_word(info, wp, data); | |
363 | +} |
@@ -0,0 +1,472 @@ | ||
1 | +/* | |
2 | + * (C) Copyright 2002 | |
3 | + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> | |
4 | + * Alex Zuepke <azu@sysgo.de> | |
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 | +#include <common.h> | |
26 | + | |
27 | +ulong myflush(void); | |
28 | + | |
29 | + | |
30 | +#define FLASH_BANK_SIZE 0x400000 /* 4 MB */ | |
31 | +#define MAIN_SECT_SIZE 0x20000 /* 128 KB */ | |
32 | + | |
33 | +flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; | |
34 | + | |
35 | + | |
36 | +#define CMD_READ_ARRAY 0x00F000F0 | |
37 | +#define CMD_UNLOCK1 0x00AA00AA | |
38 | +#define CMD_UNLOCK2 0x00550055 | |
39 | +#define CMD_ERASE_SETUP 0x00800080 | |
40 | +#define CMD_ERASE_CONFIRM 0x00300030 | |
41 | +#define CMD_PROGRAM 0x00A000A0 | |
42 | +#define CMD_UNLOCK_BYPASS 0x00200020 | |
43 | + | |
44 | +#define MEM_FLASH_ADDR1 (*(volatile u32 *)(CFG_FLASH_BASE + (0x00000555 << 2))) | |
45 | +#define MEM_FLASH_ADDR2 (*(volatile u32 *)(CFG_FLASH_BASE + (0x000002AA << 2))) | |
46 | + | |
47 | +#define BIT_ERASE_DONE 0x00800080 | |
48 | +#define BIT_RDY_MASK 0x00800080 | |
49 | +#define BIT_PROGRAM_ERROR 0x00200020 | |
50 | +#define BIT_TIMEOUT 0x80000000 /* our flag */ | |
51 | + | |
52 | +#define READY 1 | |
53 | +#define ERR 2 | |
54 | +#define TMO 4 | |
55 | + | |
56 | +/*----------------------------------------------------------------------- | |
57 | + */ | |
58 | + | |
59 | +ulong flash_init(void) | |
60 | +{ | |
61 | + int i, j; | |
62 | + ulong size = 0; | |
63 | + | |
64 | + for (i = 0; i < CFG_MAX_FLASH_BANKS; i++) | |
65 | + { | |
66 | + ulong flashbase = 0; | |
67 | + flash_info[i].flash_id = | |
68 | + (AMD_MANUFACT & FLASH_VENDMASK) | | |
69 | + (AMD_ID_LV160B & FLASH_TYPEMASK); | |
70 | + flash_info[i].size = FLASH_BANK_SIZE; | |
71 | + flash_info[i].sector_count = CFG_MAX_FLASH_SECT; | |
72 | + memset(flash_info[i].protect, 0, CFG_MAX_FLASH_SECT); | |
73 | + if (i == 0) | |
74 | + flashbase = PHYS_FLASH_1; | |
75 | + else | |
76 | + panic("configured to many flash banks!\n"); | |
77 | + for (j = 0; j < flash_info[i].sector_count; j++) | |
78 | + { | |
79 | + | |
80 | + if (j <= 3) | |
81 | + { | |
82 | + /* 1st one is 32 KB */ | |
83 | + if (j == 0) | |
84 | + { | |
85 | + flash_info[i].start[j] = flashbase + 0; | |
86 | + } | |
87 | + | |
88 | + /* 2nd and 3rd are both 16 KB */ | |
89 | + if ((j == 1) || (j == 2)) | |
90 | + { | |
91 | + flash_info[i].start[j] = flashbase + 0x8000 + (j-1)*0x4000; | |
92 | + } | |
93 | + | |
94 | + /* 4th 64 KB */ | |
95 | + if (j == 3) | |
96 | + { | |
97 | + flash_info[i].start[j] = flashbase + 0x10000; | |
98 | + } | |
99 | + } | |
100 | + else | |
101 | + { | |
102 | + flash_info[i].start[j] = flashbase + (j - 3)*MAIN_SECT_SIZE; | |
103 | + } | |
104 | + } | |
105 | + size += flash_info[i].size; | |
106 | + } | |
107 | + | |
108 | + /* | |
109 | + * Protect monitor and environment sectors | |
110 | + * Inferno is complicated, it's hardware locked | |
111 | + */ | |
112 | +#ifdef CONFIG_INFERNO | |
113 | + /* first one, 0x00000 to 0x07fff */ | |
114 | + flash_protect(FLAG_PROTECT_SET, | |
115 | + CFG_FLASH_BASE + 0x00000, | |
116 | + CFG_FLASH_BASE + 0x08000 - 1, | |
117 | + &flash_info[0]); | |
118 | + | |
119 | + /* third to 10th, 0x0c000 - 0xdffff */ | |
120 | + flash_protect(FLAG_PROTECT_SET, | |
121 | + CFG_FLASH_BASE + 0x0c000, | |
122 | + CFG_FLASH_BASE + 0xe0000 - 1, | |
123 | + &flash_info[0]); | |
124 | +#else | |
125 | + flash_protect(FLAG_PROTECT_SET, | |
126 | + CFG_FLASH_BASE, | |
127 | + CFG_FLASH_BASE + _armboot_end_data - _armboot_start, | |
128 | + &flash_info[0]); | |
129 | + | |
130 | + flash_protect(FLAG_PROTECT_SET, | |
131 | + CFG_ENV_ADDR, | |
132 | + CFG_ENV_ADDR + CFG_ENV_SIZE - 1, | |
133 | + &flash_info[0]); | |
134 | +#endif | |
135 | + return size; | |
136 | +} | |
137 | + | |
138 | +/*----------------------------------------------------------------------- | |
139 | + */ | |
140 | +void flash_print_info (flash_info_t *info) | |
141 | +{ | |
142 | + int i; | |
143 | + | |
144 | + switch (info->flash_id & FLASH_VENDMASK) | |
145 | + { | |
146 | + case (AMD_MANUFACT & FLASH_VENDMASK): | |
147 | + printf("AMD: "); | |
148 | + break; | |
149 | + default: | |
150 | + printf("Unknown Vendor "); | |
151 | + break; | |
152 | + } | |
153 | + | |
154 | + switch (info->flash_id & FLASH_TYPEMASK) | |
155 | + { | |
156 | + case (AMD_ID_LV160B & FLASH_TYPEMASK): | |
157 | + printf("2x Amd29F160BB (16Mbit)\n"); | |
158 | + break; | |
159 | + default: | |
160 | + printf("Unknown Chip Type\n"); | |
161 | + goto Done; | |
162 | + break; | |
163 | + } | |
164 | + | |
165 | + printf(" Size: %ld MB in %d Sectors\n", | |
166 | + info->size >> 20, info->sector_count); | |
167 | + | |
168 | + printf(" Sector Start Addresses:"); | |
169 | + for (i = 0; i < info->sector_count; i++) | |
170 | + { | |
171 | + if ((i % 5) == 0) | |
172 | + { | |
173 | + printf ("\n "); | |
174 | + } | |
175 | + printf (" %08lX%s", info->start[i], | |
176 | + info->protect[i] ? " (RO)" : " "); | |
177 | + } | |
178 | + printf ("\n"); | |
179 | + | |
180 | +Done: | |
181 | +} | |
182 | + | |
183 | +/*----------------------------------------------------------------------- | |
184 | + */ | |
185 | + | |
186 | +int flash_erase (flash_info_t *info, int s_first, int s_last) | |
187 | +{ | |
188 | + ulong result; | |
189 | + int iflag, cflag, prot, sect; | |
190 | + int rc = ERR_OK; | |
191 | + int chip1, chip2; | |
192 | + | |
193 | + /* first look for protection bits */ | |
194 | + | |
195 | + if (info->flash_id == FLASH_UNKNOWN) | |
196 | + return ERR_UNKNOWN_FLASH_TYPE; | |
197 | + | |
198 | + if ((s_first < 0) || (s_first > s_last)) { | |
199 | + return ERR_INVAL; | |
200 | + } | |
201 | + | |
202 | + if ((info->flash_id & FLASH_VENDMASK) != | |
203 | + (AMD_MANUFACT & FLASH_VENDMASK)) { | |
204 | + return ERR_UNKNOWN_FLASH_VENDOR; | |
205 | + } | |
206 | + | |
207 | + prot = 0; | |
208 | + for (sect=s_first; sect<=s_last; ++sect) { | |
209 | + if (info->protect[sect]) { | |
210 | + prot++; | |
211 | + } | |
212 | + } | |
213 | + if (prot) | |
214 | + return ERR_PROTECTED; | |
215 | + | |
216 | + /* | |
217 | + * Disable interrupts which might cause a timeout | |
218 | + * here. Remember that our exception vectors are | |
219 | + * at address 0 in the flash, and we don't want a | |
220 | + * (ticker) exception to happen while the flash | |
221 | + * chip is in programming mode. | |
222 | + */ | |
223 | + cflag = icache_status(); | |
224 | + icache_disable(); | |
225 | + iflag = disable_interrupts(); | |
226 | + | |
227 | + /* Start erase on unprotected sectors */ | |
228 | + for (sect = s_first; sect<=s_last && !ctrlc(); sect++) | |
229 | + { | |
230 | + printf("Erasing sector %2d ... ", sect); | |
231 | + | |
232 | + /* arm simple, non interrupt dependent timer */ | |
233 | + reset_timer_masked(); | |
234 | + | |
235 | + if (info->protect[sect] == 0) | |
236 | + { /* not protected */ | |
237 | + vu_long *addr = (vu_long *)(info->start[sect]); | |
238 | + | |
239 | + MEM_FLASH_ADDR1 = CMD_UNLOCK1; | |
240 | + MEM_FLASH_ADDR2 = CMD_UNLOCK2; | |
241 | + MEM_FLASH_ADDR1 = CMD_ERASE_SETUP; | |
242 | + | |
243 | + MEM_FLASH_ADDR1 = CMD_UNLOCK1; | |
244 | + MEM_FLASH_ADDR2 = CMD_UNLOCK2; | |
245 | + *addr = CMD_ERASE_CONFIRM; | |
246 | + | |
247 | + /* wait until flash is ready */ | |
248 | + chip1 = chip2 = 0; | |
249 | + | |
250 | + do | |
251 | + { | |
252 | + result = *addr; | |
253 | + | |
254 | + /* check timeout */ | |
255 | + if (get_timer_masked() > CFG_FLASH_ERASE_TOUT) | |
256 | + { | |
257 | + MEM_FLASH_ADDR1 = CMD_READ_ARRAY; | |
258 | + chip1 = TMO; | |
259 | + break; | |
260 | + } | |
261 | + | |
262 | + if (!chip1 && (result & 0xFFFF) & BIT_ERASE_DONE) | |
263 | + chip1 = READY; | |
264 | + | |
265 | + if (!chip1 && (result & 0xFFFF) & BIT_PROGRAM_ERROR) | |
266 | + chip1 = ERR; | |
267 | + | |
268 | + if (!chip2 && (result >> 16) & BIT_ERASE_DONE) | |
269 | + chip2 = READY; | |
270 | + | |
271 | + if (!chip2 && (result >> 16) & BIT_PROGRAM_ERROR) | |
272 | + chip2 = ERR; | |
273 | + | |
274 | + } while (!chip1 || !chip2); | |
275 | + | |
276 | + MEM_FLASH_ADDR1 = CMD_READ_ARRAY; | |
277 | + | |
278 | + if (chip1 == ERR || chip2 == ERR) | |
279 | + { | |
280 | + rc = ERR_PROG_ERROR; | |
281 | + goto outahere; | |
282 | + } | |
283 | + if (chip1 == TMO) | |
284 | + { | |
285 | + rc = ERR_TIMOUT; | |
286 | + goto outahere; | |
287 | + } | |
288 | + | |
289 | + printf("ok.\n"); | |
290 | + } | |
291 | + else /* it was protected */ | |
292 | + { | |
293 | + printf("protected!\n"); | |
294 | + } | |
295 | + } | |
296 | + | |
297 | + if (ctrlc()) | |
298 | + printf("User Interrupt!\n"); | |
299 | + | |
300 | +outahere: | |
301 | + /* allow flash to settle - wait 10 ms */ | |
302 | + udelay_masked(10000); | |
303 | + | |
304 | + if (iflag) | |
305 | + enable_interrupts(); | |
306 | + | |
307 | + if (cflag) | |
308 | + icache_enable(); | |
309 | + | |
310 | + return rc; | |
311 | +} | |
312 | + | |
313 | +/*----------------------------------------------------------------------- | |
314 | + * Copy memory to flash | |
315 | + */ | |
316 | + | |
317 | +volatile static int write_word (flash_info_t *info, ulong dest, ulong data) | |
318 | +{ | |
319 | + vu_long *addr = (vu_long *)dest; | |
320 | + ulong result; | |
321 | + int rc = ERR_OK; | |
322 | + int cflag, iflag; | |
323 | + int chip1, chip2; | |
324 | + | |
325 | + /* | |
326 | + * Check if Flash is (sufficiently) erased | |
327 | + */ | |
328 | + result = *addr; | |
329 | + if ((result & data) != data) | |
330 | + return ERR_NOT_ERASED; | |
331 | + | |
332 | + | |
333 | + /* | |
334 | + * Disable interrupts which might cause a timeout | |
335 | + * here. Remember that our exception vectors are | |
336 | + * at address 0 in the flash, and we don't want a | |
337 | + * (ticker) exception to happen while the flash | |
338 | + * chip is in programming mode. | |
339 | + */ | |
340 | + cflag = icache_status(); | |
341 | + icache_disable(); | |
342 | + iflag = disable_interrupts(); | |
343 | + | |
344 | + MEM_FLASH_ADDR1 = CMD_UNLOCK1; | |
345 | + MEM_FLASH_ADDR2 = CMD_UNLOCK2; | |
346 | + MEM_FLASH_ADDR1 = CMD_UNLOCK_BYPASS; | |
347 | + *addr = CMD_PROGRAM; | |
348 | + *addr = data; | |
349 | + | |
350 | + /* arm simple, non interrupt dependent timer */ | |
351 | + reset_timer_masked(); | |
352 | + | |
353 | + /* wait until flash is ready */ | |
354 | + chip1 = chip2 = 0; | |
355 | + do | |
356 | + { | |
357 | + result = *addr; | |
358 | + | |
359 | + /* check timeout */ | |
360 | + if (get_timer_masked() > CFG_FLASH_ERASE_TOUT) | |
361 | + { | |
362 | + chip1 = ERR | TMO; | |
363 | + break; | |
364 | + } | |
365 | + if (!chip1 && ((result & 0x80) == (data & 0x80))) | |
366 | + chip1 = READY; | |
367 | + | |
368 | + if (!chip1 && ((result & 0xFFFF) & BIT_PROGRAM_ERROR)) | |
369 | + { | |
370 | + result = *addr; | |
371 | + | |
372 | + if ((result & 0x80) == (data & 0x80)) | |
373 | + chip1 = READY; | |
374 | + else | |
375 | + chip1 = ERR; | |
376 | + } | |
377 | + | |
378 | + if (!chip2 && ((result & (0x80 << 16)) == (data & (0x80 << 16)))) | |
379 | + chip2 = READY; | |
380 | + | |
381 | + if (!chip2 && ((result >> 16) & BIT_PROGRAM_ERROR)) | |
382 | + { | |
383 | + result = *addr; | |
384 | + | |
385 | + if ((result & (0x80 << 16)) == (data & (0x80 << 16))) | |
386 | + chip2 = READY; | |
387 | + else | |
388 | + chip2 = ERR; | |
389 | + } | |
390 | + | |
391 | + } while (!chip1 || !chip2); | |
392 | + | |
393 | + *addr = CMD_READ_ARRAY; | |
394 | + | |
395 | + if (chip1 == ERR || chip2 == ERR || *addr != data) | |
396 | + rc = ERR_PROG_ERROR; | |
397 | + | |
398 | + if (iflag) | |
399 | + enable_interrupts(); | |
400 | + | |
401 | + if (cflag) | |
402 | + icache_enable(); | |
403 | + | |
404 | + return rc; | |
405 | +} | |
406 | + | |
407 | +/*----------------------------------------------------------------------- | |
408 | + * Copy memory to flash. | |
409 | + */ | |
410 | + | |
411 | +int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt) | |
412 | +{ | |
413 | + ulong cp, wp, data; | |
414 | + int l; | |
415 | + int i, rc; | |
416 | + | |
417 | + wp = (addr & ~3); /* get lower word aligned address */ | |
418 | + | |
419 | + /* | |
420 | + * handle unaligned start bytes | |
421 | + */ | |
422 | + if ((l = addr - wp) != 0) { | |
423 | + data = 0; | |
424 | + for (i=0, cp=wp; i<l; ++i, ++cp) { | |
425 | + data = (data >> 8) | (*(uchar *)cp << 24); | |
426 | + } | |
427 | + for (; i<4 && cnt>0; ++i) { | |
428 | + data = (data >> 8) | (*src++ << 24); | |
429 | + --cnt; | |
430 | + ++cp; | |
431 | + } | |
432 | + for (; cnt==0 && i<4; ++i, ++cp) { | |
433 | + data = (data >> 8) | (*(uchar *)cp << 24); | |
434 | + } | |
435 | + | |
436 | + if ((rc = write_word(info, wp, data)) != 0) { | |
437 | + return (rc); | |
438 | + } | |
439 | + wp += 4; | |
440 | + } | |
441 | + | |
442 | + /* | |
443 | + * handle word aligned part | |
444 | + */ | |
445 | + while (cnt >= 4) { | |
446 | + data = *((vu_long*)src); | |
447 | + if ((rc = write_word(info, wp, data)) != 0) { | |
448 | + return (rc); | |
449 | + } | |
450 | + src += 4; | |
451 | + wp += 4; | |
452 | + cnt -= 4; | |
453 | + } | |
454 | + | |
455 | + if (cnt == 0) { | |
456 | + return ERR_OK; | |
457 | + } | |
458 | + | |
459 | + /* | |
460 | + * handle unaligned tail bytes | |
461 | + */ | |
462 | + data = 0; | |
463 | + for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) { | |
464 | + data = (data >> 8) | (*src++ << 24); | |
465 | + --cnt; | |
466 | + } | |
467 | + for (; i<4; ++i, ++cp) { | |
468 | + data = (data >> 8) | (*(uchar *)cp << 24); | |
469 | + } | |
470 | + | |
471 | + return write_word(info, wp, data); | |
472 | +} |
@@ -0,0 +1,491 @@ | ||
1 | +/* | |
2 | + * (C) Copyright 2002 | |
3 | + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> | |
4 | + * Marius Groeger <mgroeger@sysgo.de> | |
5 | + * | |
6 | + * (C) Copyright 2002 | |
7 | + * Gary Jennejohn, DENX Software Engineering, <gj@denx.de> | |
8 | + * | |
9 | + * See file CREDITS for list of people who contributed to this | |
10 | + * project. | |
11 | + * | |
12 | + * This program is free software; you can redistribute it and/or | |
13 | + * modify it under the terms of the GNU General Public License as | |
14 | + * published by the Free Software Foundation; either version 2 of | |
15 | + * the License, or (at your option) any later version. | |
16 | + * | |
17 | + * This program is distributed in the hope that it will be useful, | |
18 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
19 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
20 | + * GNU General Public License for more details. | |
21 | + * | |
22 | + * You should have received a copy of the GNU General Public License | |
23 | + * along with this program; if not, write to the Free Software | |
24 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
25 | + * MA 02111-1307 USA | |
26 | + */ | |
27 | + | |
28 | +/* #define DEBUG */ | |
29 | + | |
30 | +#include <common.h> | |
31 | +#include <environment.h> | |
32 | + | |
33 | +#define FLASH_BANK_SIZE 0x1000000 /* 2 x 8 MB */ | |
34 | +#define MAIN_SECT_SIZE 0x40000 /* 2 x 128 kB */ | |
35 | + | |
36 | +flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; | |
37 | + | |
38 | + | |
39 | +#define CMD_READ_ARRAY 0x00FF00FF | |
40 | +#define CMD_IDENTIFY 0x00900090 | |
41 | +#define CMD_ERASE_SETUP 0x00200020 | |
42 | +#define CMD_ERASE_CONFIRM 0x00D000D0 | |
43 | +#define CMD_PROGRAM 0x00400040 | |
44 | +#define CMD_RESUME 0x00D000D0 | |
45 | +#define CMD_SUSPEND 0x00B000B0 | |
46 | +#define CMD_STATUS_READ 0x00700070 | |
47 | +#define CMD_STATUS_RESET 0x00500050 | |
48 | + | |
49 | +#define BIT_BUSY 0x00800080 | |
50 | +#define BIT_ERASE_SUSPEND 0x00400040 | |
51 | +#define BIT_ERASE_ERROR 0x00200020 | |
52 | +#define BIT_PROGRAM_ERROR 0x00100010 | |
53 | +#define BIT_VPP_RANGE_ERROR 0x00080008 | |
54 | +#define BIT_PROGRAM_SUSPEND 0x00040004 | |
55 | +#define BIT_PROTECT_ERROR 0x00020002 | |
56 | +#define BIT_UNDEFINED 0x00010001 | |
57 | + | |
58 | +#define BIT_SEQUENCE_ERROR 0x00300030 | |
59 | +#define BIT_TIMEOUT 0x80000000 | |
60 | + | |
61 | +/*----------------------------------------------------------------------- | |
62 | + */ | |
63 | + | |
64 | +ulong flash_init (void) | |
65 | +{ | |
66 | + int i, j; | |
67 | + ulong size = 0; | |
68 | + | |
69 | + for (i = 0; i < CFG_MAX_FLASH_BANKS; i++) { | |
70 | + ulong flashbase = 0; | |
71 | + | |
72 | + flash_info[i].flash_id = | |
73 | + (INTEL_MANUFACT & FLASH_VENDMASK) | | |
74 | + (INTEL_ID_28F640J3A & FLASH_TYPEMASK); | |
75 | + flash_info[i].size = FLASH_BANK_SIZE; | |
76 | + flash_info[i].sector_count = CFG_MAX_FLASH_SECT; | |
77 | + memset (flash_info[i].protect, 0, CFG_MAX_FLASH_SECT); | |
78 | + if (i == 0) | |
79 | + flashbase = PHYS_FLASH_1; | |
80 | + else | |
81 | + panic ("configured too many flash banks!\n"); | |
82 | + for (j = 0; j < flash_info[i].sector_count; j++) { | |
83 | + flash_info[i].start[j] = flashbase; | |
84 | + | |
85 | + /* uniform sector size */ | |
86 | + flashbase += MAIN_SECT_SIZE; | |
87 | + } | |
88 | + size += flash_info[i].size; | |
89 | + } | |
90 | + | |
91 | + /* | |
92 | + * Protect monitor and environment sectors | |
93 | + */ | |
94 | + flash_protect ( FLAG_PROTECT_SET, | |
95 | + CFG_FLASH_BASE, | |
96 | + CFG_FLASH_BASE + _armboot_end_data - _armboot_start, | |
97 | + &flash_info[0]); | |
98 | + | |
99 | + flash_protect ( FLAG_PROTECT_SET, | |
100 | + CFG_ENV_ADDR, | |
101 | + CFG_ENV_ADDR + CFG_ENV_SIZE - 1, &flash_info[0]); | |
102 | + | |
103 | +#ifdef CFG_ENV_ADDR_REDUND | |
104 | + flash_protect ( FLAG_PROTECT_SET, | |
105 | + CFG_ENV_ADDR_REDUND, | |
106 | + CFG_ENV_ADDR_REDUND + CFG_ENV_SIZE_REDUND - 1, | |
107 | + &flash_info[0]); | |
108 | +#endif | |
109 | + | |
110 | + return size; | |
111 | +} | |
112 | + | |
113 | +/*----------------------------------------------------------------------- | |
114 | + */ | |
115 | +void flash_print_info (flash_info_t * info) | |
116 | +{ | |
117 | + int i; | |
118 | + | |
119 | + switch (info->flash_id & FLASH_VENDMASK) { | |
120 | + case (INTEL_MANUFACT & FLASH_VENDMASK): | |
121 | + printf ("Intel: "); | |
122 | + break; | |
123 | + default: | |
124 | + printf ("Unknown Vendor "); | |
125 | + break; | |
126 | + } | |
127 | + | |
128 | + switch (info->flash_id & FLASH_TYPEMASK) { | |
129 | + case (INTEL_ID_28F640J3A & FLASH_TYPEMASK): | |
130 | + printf ("2x 28F640J3A (64Mbit)\n"); | |
131 | + break; | |
132 | + default: | |
133 | + printf ("Unknown Chip Type\n"); | |
134 | + goto Done; | |
135 | + break; | |
136 | + } | |
137 | + | |
138 | + printf (" Size: %ld MB in %d Sectors\n", | |
139 | + info->size >> 20, info->sector_count); | |
140 | + | |
141 | + printf (" Sector Start Addresses:"); | |
142 | + for (i = 0; i < info->sector_count; i++) { | |
143 | + if ((i % 5) == 0) { | |
144 | + printf ("\n "); | |
145 | + } | |
146 | + printf (" %08lX%s", | |
147 | + info->start[i], | |
148 | + info->protect[i] ? " (RO)" : " "); | |
149 | + } | |
150 | + printf ("\n"); | |
151 | + | |
152 | + Done: | |
153 | +} | |
154 | + | |
155 | +/*----------------------------------------------------------------------- | |
156 | + */ | |
157 | + | |
158 | +int flash_error (ulong code) | |
159 | +{ | |
160 | + /* Check bit patterns */ | |
161 | + /* SR.7=0 is busy, SR.7=1 is ready */ | |
162 | + /* all other flags indicate error on 1 */ | |
163 | + /* SR.0 is undefined */ | |
164 | + /* Timeout is our faked flag */ | |
165 | + | |
166 | + /* sequence is described in Intel 290644-005 document */ | |
167 | + | |
168 | + /* check Timeout */ | |
169 | + if (code & BIT_TIMEOUT) { | |
170 | + puts ("Timeout\n"); | |
171 | + return ERR_TIMOUT; | |
172 | + } | |
173 | + | |
174 | + /* check Busy, SR.7 */ | |
175 | + if (~code & BIT_BUSY) { | |
176 | + puts ("Busy\n"); | |
177 | + return ERR_PROG_ERROR; | |
178 | + } | |
179 | + | |
180 | + /* check Vpp low, SR.3 */ | |
181 | + if (code & BIT_VPP_RANGE_ERROR) { | |
182 | + puts ("Vpp range error\n"); | |
183 | + return ERR_PROG_ERROR; | |
184 | + } | |
185 | + | |
186 | + /* check Device Protect Error, SR.1 */ | |
187 | + if (code & BIT_PROTECT_ERROR) { | |
188 | + puts ("Device protect error\n"); | |
189 | + return ERR_PROG_ERROR; | |
190 | + } | |
191 | + | |
192 | + /* check Command Seq Error, SR.4 & SR.5 */ | |
193 | + if (code & BIT_SEQUENCE_ERROR) { | |
194 | + puts ("Command seqence error\n"); | |
195 | + return ERR_PROG_ERROR; | |
196 | + } | |
197 | + | |
198 | + /* check Block Erase Error, SR.5 */ | |
199 | + if (code & BIT_ERASE_ERROR) { | |
200 | + puts ("Block erase error\n"); | |
201 | + return ERR_PROG_ERROR; | |
202 | + } | |
203 | + | |
204 | + /* check Program Error, SR.4 */ | |
205 | + if (code & BIT_PROGRAM_ERROR) { | |
206 | + puts ("Program error\n"); | |
207 | + return ERR_PROG_ERROR; | |
208 | + } | |
209 | + | |
210 | + /* check Block Erase Suspended, SR.6 */ | |
211 | + if (code & BIT_ERASE_SUSPEND) { | |
212 | + puts ("Block erase suspended\n"); | |
213 | + return ERR_PROG_ERROR; | |
214 | + } | |
215 | + | |
216 | + /* check Program Suspended, SR.2 */ | |
217 | + if (code & BIT_PROGRAM_SUSPEND) { | |
218 | + puts ("Program suspended\n"); | |
219 | + return ERR_PROG_ERROR; | |
220 | + } | |
221 | + | |
222 | + /* OK, no error */ | |
223 | + return ERR_OK; | |
224 | +} | |
225 | + | |
226 | +/*----------------------------------------------------------------------- | |
227 | + */ | |
228 | + | |
229 | +int flash_erase (flash_info_t * info, int s_first, int s_last) | |
230 | +{ | |
231 | + ulong result, result1; | |
232 | + int iflag, prot, sect; | |
233 | + int rc = ERR_OK; | |
234 | + | |
235 | +#ifdef USE_920T_MMU | |
236 | + int cflag; | |
237 | +#endif | |
238 | + | |
239 | + debug ("flash_erase: s_first %d s_last %d\n", s_first, s_last); | |
240 | + | |
241 | + /* first look for protection bits */ | |
242 | + | |
243 | + if (info->flash_id == FLASH_UNKNOWN) | |
244 | + return ERR_UNKNOWN_FLASH_TYPE; | |
245 | + | |
246 | + if ((s_first < 0) || (s_first > s_last)) { | |
247 | + return ERR_INVAL; | |
248 | + } | |
249 | + | |
250 | + if ((info->flash_id & FLASH_VENDMASK) != | |
251 | + (INTEL_MANUFACT & FLASH_VENDMASK)) { | |
252 | + return ERR_UNKNOWN_FLASH_VENDOR; | |
253 | + } | |
254 | + | |
255 | + prot = 0; | |
256 | + for (sect = s_first; sect <= s_last; ++sect) { | |
257 | + if (info->protect[sect]) { | |
258 | + prot++; | |
259 | + } | |
260 | + } | |
261 | + | |
262 | + if (prot) { | |
263 | + printf ("- Warning: %d protected sectors will not be erased!\n", | |
264 | + prot); | |
265 | + } else { | |
266 | + printf ("\n"); | |
267 | + } | |
268 | + | |
269 | + /* | |
270 | + * Disable interrupts which might cause a timeout | |
271 | + * here. Remember that our exception vectors are | |
272 | + * at address 0 in the flash, and we don't want a | |
273 | + * (ticker) exception to happen while the flash | |
274 | + * chip is in programming mode. | |
275 | + */ | |
276 | +#ifdef USE_920T_MMU | |
277 | + cflag = dcache_status (); | |
278 | + dcache_disable (); | |
279 | +#endif | |
280 | + iflag = disable_interrupts (); | |
281 | + | |
282 | + /* Start erase on unprotected sectors */ | |
283 | + for (sect = s_first; sect <= s_last && !ctrlc (); sect++) { | |
284 | + | |
285 | + debug ("Erasing sector %2d @ %08lX... ", | |
286 | + sect, info->start[sect]); | |
287 | + | |
288 | + /* arm simple, non interrupt dependent timer */ | |
289 | + reset_timer_masked (); | |
290 | + | |
291 | + if (info->protect[sect] == 0) { /* not protected */ | |
292 | + vu_long *addr = (vu_long *) (info->start[sect]); | |
293 | + ulong bsR7, bsR7_2, bsR5, bsR5_2; | |
294 | + | |
295 | + /* *addr = CMD_STATUS_RESET; */ | |
296 | + *addr = CMD_ERASE_SETUP; | |
297 | + *addr = CMD_ERASE_CONFIRM; | |
298 | + | |
299 | + /* wait until flash is ready */ | |
300 | + do { | |
301 | + /* check timeout */ | |
302 | + if (get_timer_masked () > CFG_FLASH_ERASE_TOUT) { | |
303 | + *addr = CMD_STATUS_RESET; | |
304 | + result = BIT_TIMEOUT; | |
305 | + break; | |
306 | + } | |
307 | + | |
308 | + *addr = CMD_STATUS_READ; | |
309 | + result = *addr; | |
310 | + bsR7 = result & (1 << 7); | |
311 | + bsR7_2 = result & (1 << 23); | |
312 | + } while (!bsR7 | !bsR7_2); | |
313 | + | |
314 | + *addr = CMD_STATUS_READ; | |
315 | + result1 = *addr; | |
316 | + bsR5 = result1 & (1 << 5); | |
317 | + bsR5_2 = result1 & (1 << 21); | |
318 | +#ifdef SAMSUNG_FLASH_DEBUG | |
319 | + printf ("bsR5 %lx bsR5_2 %lx\n", bsR5, bsR5_2); | |
320 | + if (bsR5 != 0 && bsR5_2 != 0) | |
321 | + printf ("bsR5 %lx bsR5_2 %lx\n", bsR5, bsR5_2); | |
322 | +#endif | |
323 | + | |
324 | + *addr = CMD_READ_ARRAY; | |
325 | + *addr = CMD_RESUME; | |
326 | + | |
327 | + if ((rc = flash_error (result)) != ERR_OK) | |
328 | + goto outahere; | |
329 | +#if 0 | |
330 | + printf ("ok.\n"); | |
331 | + } else { /* it was protected */ | |
332 | + | |
333 | + printf ("protected!\n"); | |
334 | +#endif | |
335 | + } | |
336 | + } | |
337 | + | |
338 | +outahere: | |
339 | + /* allow flash to settle - wait 10 ms */ | |
340 | + udelay_masked (10000); | |
341 | + | |
342 | + if (iflag) | |
343 | + enable_interrupts (); | |
344 | + | |
345 | +#ifdef USE_920T_MMU | |
346 | + if (cflag) | |
347 | + dcache_enable (); | |
348 | +#endif | |
349 | + return rc; | |
350 | +} | |
351 | + | |
352 | +/*----------------------------------------------------------------------- | |
353 | + * Copy memory to flash | |
354 | + */ | |
355 | + | |
356 | +volatile static int write_word (flash_info_t * info, ulong dest, | |
357 | + ulong data) | |
358 | +{ | |
359 | + vu_long *addr = (vu_long *) dest; | |
360 | + ulong result; | |
361 | + int rc = ERR_OK; | |
362 | + int iflag; | |
363 | + | |
364 | +#ifdef USE_920T_MMU | |
365 | + int cflag; | |
366 | +#endif | |
367 | + | |
368 | + /* | |
369 | + * Check if Flash is (sufficiently) erased | |
370 | + */ | |
371 | + result = *addr; | |
372 | + if ((result & data) != data) | |
373 | + return ERR_NOT_ERASED; | |
374 | + | |
375 | + /* | |
376 | + * Disable interrupts which might cause a timeout | |
377 | + * here. Remember that our exception vectors are | |
378 | + * at address 0 in the flash, and we don't want a | |
379 | + * (ticker) exception to happen while the flash | |
380 | + * chip is in programming mode. | |
381 | + */ | |
382 | +#ifdef USE_920T_MMU | |
383 | + cflag = dcache_status (); | |
384 | + dcache_disable (); | |
385 | +#endif | |
386 | + iflag = disable_interrupts (); | |
387 | + | |
388 | + /* *addr = CMD_STATUS_RESET; */ | |
389 | + *addr = CMD_PROGRAM; | |
390 | + *addr = data; | |
391 | + | |
392 | + /* arm simple, non interrupt dependent timer */ | |
393 | + reset_timer_masked (); | |
394 | + | |
395 | + /* wait until flash is ready */ | |
396 | + do { | |
397 | + /* check timeout */ | |
398 | + if (get_timer_masked () > CFG_FLASH_ERASE_TOUT) { | |
399 | + *addr = CMD_SUSPEND; | |
400 | + result = BIT_TIMEOUT; | |
401 | + break; | |
402 | + } | |
403 | + | |
404 | + *addr = CMD_STATUS_READ; | |
405 | + result = *addr; | |
406 | + } while (~result & BIT_BUSY); | |
407 | + | |
408 | + /* *addr = CMD_READ_ARRAY; */ | |
409 | + *addr = CMD_STATUS_READ; | |
410 | + result = *addr; | |
411 | + | |
412 | + rc = flash_error (result); | |
413 | + | |
414 | + if (iflag) | |
415 | + enable_interrupts (); | |
416 | + | |
417 | +#ifdef USE_920T_MMU | |
418 | + if (cflag) | |
419 | + dcache_enable (); | |
420 | +#endif | |
421 | + *addr = CMD_READ_ARRAY; | |
422 | + *addr = CMD_RESUME; | |
423 | + return rc; | |
424 | +} | |
425 | + | |
426 | +/*----------------------------------------------------------------------- | |
427 | + * Copy memory to flash. | |
428 | + */ | |
429 | + | |
430 | +int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt) | |
431 | +{ | |
432 | + ulong cp, wp, data; | |
433 | + int l; | |
434 | + int i, rc; | |
435 | + | |
436 | + wp = (addr & ~3); /* get lower word aligned address */ | |
437 | + | |
438 | + /* | |
439 | + * handle unaligned start bytes | |
440 | + */ | |
441 | + if ((l = addr - wp) != 0) { | |
442 | + data = 0; | |
443 | + for (i = 0, cp = wp; i < l; ++i, ++cp) { | |
444 | + data = (data >> 8) | (*(uchar *) cp << 24); | |
445 | + } | |
446 | + for (; i < 4 && cnt > 0; ++i) { | |
447 | + data = (data >> 8) | (*src++ << 24); | |
448 | + --cnt; | |
449 | + ++cp; | |
450 | + } | |
451 | + for (; cnt == 0 && i < 4; ++i, ++cp) { | |
452 | + data = (data >> 8) | (*(uchar *) cp << 24); | |
453 | + } | |
454 | + | |
455 | + if ((rc = write_word (info, wp, data)) != 0) { | |
456 | + return (rc); | |
457 | + } | |
458 | + wp += 4; | |
459 | + } | |
460 | + | |
461 | + /* | |
462 | + * handle word aligned part | |
463 | + */ | |
464 | + while (cnt >= 4) { | |
465 | + data = *((vu_long *) src); | |
466 | + if ((rc = write_word (info, wp, data)) != 0) { | |
467 | + return (rc); | |
468 | + } | |
469 | + src += 4; | |
470 | + wp += 4; | |
471 | + cnt -= 4; | |
472 | + } | |
473 | + | |
474 | + if (cnt == 0) { | |
475 | + return ERR_OK; | |
476 | + } | |
477 | + | |
478 | + /* | |
479 | + * handle unaligned tail bytes | |
480 | + */ | |
481 | + data = 0; | |
482 | + for (i = 0, cp = wp; i < 4 && cnt > 0; ++i, ++cp) { | |
483 | + data = (data >> 8) | (*src++ << 24); | |
484 | + --cnt; | |
485 | + } | |
486 | + for (; i < 4; ++i, ++cp) { | |
487 | + data = (data >> 8) | (*(uchar *) cp << 24); | |
488 | + } | |
489 | + | |
490 | + return write_word (info, wp, data); | |
491 | +} |
@@ -0,0 +1,446 @@ | ||
1 | +/* | |
2 | + * (C) Copyright 2002 | |
3 | + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> | |
4 | + * Alex Zuepke <azu@sysgo.de> | |
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 | +#include <common.h> | |
26 | + | |
27 | +ulong myflush(void); | |
28 | + | |
29 | + | |
30 | +#define FLASH_BANK_SIZE PHYS_FLASH_SIZE | |
31 | +#define MAIN_SECT_SIZE 0x10000 /* 64 KB */ | |
32 | + | |
33 | +flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; | |
34 | + | |
35 | + | |
36 | +#define CMD_READ_ARRAY 0x000000F0 | |
37 | +#define CMD_UNLOCK1 0x000000AA | |
38 | +#define CMD_UNLOCK2 0x00000055 | |
39 | +#define CMD_ERASE_SETUP 0x00000080 | |
40 | +#define CMD_ERASE_CONFIRM 0x00000030 | |
41 | +#define CMD_PROGRAM 0x000000A0 | |
42 | +#define CMD_UNLOCK_BYPASS 0x00000020 | |
43 | + | |
44 | +#define MEM_FLASH_ADDR1 (*(volatile u16 *)(CFG_FLASH_BASE + (0x00000555 << 1))) | |
45 | +#define MEM_FLASH_ADDR2 (*(volatile u16 *)(CFG_FLASH_BASE + (0x000002AA << 1))) | |
46 | + | |
47 | +#define BIT_ERASE_DONE 0x00000080 | |
48 | +#define BIT_RDY_MASK 0x00000080 | |
49 | +#define BIT_PROGRAM_ERROR 0x00000020 | |
50 | +#define BIT_TIMEOUT 0x80000000 /* our flag */ | |
51 | + | |
52 | +#define READY 1 | |
53 | +#define ERR 2 | |
54 | +#define TMO 4 | |
55 | + | |
56 | +/*----------------------------------------------------------------------- | |
57 | + */ | |
58 | + | |
59 | +ulong flash_init(void) | |
60 | +{ | |
61 | + int i, j; | |
62 | + ulong size = 0; | |
63 | + | |
64 | + for (i = 0; i < CFG_MAX_FLASH_BANKS; i++) | |
65 | + { | |
66 | + ulong flashbase = 0; | |
67 | + flash_info[i].flash_id = | |
68 | +#if defined(CONFIG_AMD_LV400) | |
69 | + (AMD_MANUFACT & FLASH_VENDMASK) | | |
70 | + (AMD_ID_LV400B & FLASH_TYPEMASK); | |
71 | +#elif defined(CONFIG_AMD_LV800) | |
72 | + (AMD_MANUFACT & FLASH_VENDMASK) | | |
73 | + (AMD_ID_LV800B & FLASH_TYPEMASK); | |
74 | +#else | |
75 | +#error "Unknown flash configured" | |
76 | +#endif | |
77 | + flash_info[i].size = FLASH_BANK_SIZE; | |
78 | + flash_info[i].sector_count = CFG_MAX_FLASH_SECT; | |
79 | + memset(flash_info[i].protect, 0, CFG_MAX_FLASH_SECT); | |
80 | + if (i == 0) | |
81 | + flashbase = PHYS_FLASH_1; | |
82 | + else | |
83 | + panic("configured to many flash banks!\n"); | |
84 | + for (j = 0; j < flash_info[i].sector_count; j++) | |
85 | + { | |
86 | + if (j <= 3) | |
87 | + { | |
88 | + /* 1st one is 16 KB */ | |
89 | + if (j == 0) | |
90 | + { | |
91 | + flash_info[i].start[j] = flashbase + 0; | |
92 | + } | |
93 | + | |
94 | + /* 2nd and 3rd are both 8 KB */ | |
95 | + if ((j == 1) || (j == 2)) | |
96 | + { | |
97 | + flash_info[i].start[j] = flashbase + 0x4000 + (j-1)*0x2000; | |
98 | + } | |
99 | + | |
100 | + /* 4th 32 KB */ | |
101 | + if (j == 3) | |
102 | + { | |
103 | + flash_info[i].start[j] = flashbase + 0x8000; | |
104 | + } | |
105 | + } | |
106 | + else | |
107 | + { | |
108 | + flash_info[i].start[j] = flashbase + (j - 3)*MAIN_SECT_SIZE; | |
109 | + } | |
110 | + } | |
111 | + size += flash_info[i].size; | |
112 | + } | |
113 | + | |
114 | + flash_protect(FLAG_PROTECT_SET, | |
115 | + CFG_FLASH_BASE, | |
116 | + CFG_FLASH_BASE + _armboot_end_data - _armboot_start, | |
117 | + &flash_info[0]); | |
118 | + | |
119 | + flash_protect(FLAG_PROTECT_SET, | |
120 | + CFG_ENV_ADDR, | |
121 | + CFG_ENV_ADDR + CFG_ENV_SIZE - 1, | |
122 | + &flash_info[0]); | |
123 | + | |
124 | + return size; | |
125 | +} | |
126 | + | |
127 | +/*----------------------------------------------------------------------- | |
128 | + */ | |
129 | +void flash_print_info (flash_info_t *info) | |
130 | +{ | |
131 | + int i; | |
132 | + | |
133 | + switch (info->flash_id & FLASH_VENDMASK) | |
134 | + { | |
135 | + case (AMD_MANUFACT & FLASH_VENDMASK): | |
136 | + printf("AMD: "); | |
137 | + break; | |
138 | + default: | |
139 | + printf("Unknown Vendor "); | |
140 | + break; | |
141 | + } | |
142 | + | |
143 | + switch (info->flash_id & FLASH_TYPEMASK) | |
144 | + { | |
145 | + case (AMD_ID_LV400B & FLASH_TYPEMASK): | |
146 | + printf("1x Amd29LV400BB (4Mbit)\n"); | |
147 | + break; | |
148 | + case (AMD_ID_LV800B & FLASH_TYPEMASK): | |
149 | + printf("1x Amd29LV800BB (8Mbit)\n"); | |
150 | + break; | |
151 | + default: | |
152 | + printf("Unknown Chip Type\n"); | |
153 | + goto Done; | |
154 | + break; | |
155 | + } | |
156 | + | |
157 | + printf(" Size: %ld MB in %d Sectors\n", | |
158 | + info->size >> 20, info->sector_count); | |
159 | + | |
160 | + printf(" Sector Start Addresses:"); | |
161 | + for (i = 0; i < info->sector_count; i++) | |
162 | + { | |
163 | + if ((i % 5) == 0) | |
164 | + { | |
165 | + printf ("\n "); | |
166 | + } | |
167 | + printf (" %08lX%s", info->start[i], | |
168 | + info->protect[i] ? " (RO)" : " "); | |
169 | + } | |
170 | + printf ("\n"); | |
171 | + | |
172 | +Done: | |
173 | +} | |
174 | + | |
175 | +/*----------------------------------------------------------------------- | |
176 | + */ | |
177 | + | |
178 | +int flash_erase (flash_info_t *info, int s_first, int s_last) | |
179 | +{ | |
180 | + ushort result; | |
181 | + int iflag, cflag, prot, sect; | |
182 | + int rc = ERR_OK; | |
183 | + int chip; | |
184 | + | |
185 | + /* first look for protection bits */ | |
186 | + | |
187 | + if (info->flash_id == FLASH_UNKNOWN) | |
188 | + return ERR_UNKNOWN_FLASH_TYPE; | |
189 | + | |
190 | + if ((s_first < 0) || (s_first > s_last)) { | |
191 | + return ERR_INVAL; | |
192 | + } | |
193 | + | |
194 | + if ((info->flash_id & FLASH_VENDMASK) != | |
195 | + (AMD_MANUFACT & FLASH_VENDMASK)) { | |
196 | + return ERR_UNKNOWN_FLASH_VENDOR; | |
197 | + } | |
198 | + | |
199 | + prot = 0; | |
200 | + for (sect=s_first; sect<=s_last; ++sect) { | |
201 | + if (info->protect[sect]) { | |
202 | + prot++; | |
203 | + } | |
204 | + } | |
205 | + if (prot) | |
206 | + return ERR_PROTECTED; | |
207 | + | |
208 | + /* | |
209 | + * Disable interrupts which might cause a timeout | |
210 | + * here. Remember that our exception vectors are | |
211 | + * at address 0 in the flash, and we don't want a | |
212 | + * (ticker) exception to happen while the flash | |
213 | + * chip is in programming mode. | |
214 | + */ | |
215 | + cflag = icache_status(); | |
216 | + icache_disable(); | |
217 | + iflag = disable_interrupts(); | |
218 | + | |
219 | + /* Start erase on unprotected sectors */ | |
220 | + for (sect = s_first; sect<=s_last && !ctrlc(); sect++) | |
221 | + { | |
222 | + printf("Erasing sector %2d ... ", sect); | |
223 | + | |
224 | + /* arm simple, non interrupt dependent timer */ | |
225 | + reset_timer_masked(); | |
226 | + | |
227 | + if (info->protect[sect] == 0) | |
228 | + { /* not protected */ | |
229 | + vu_short *addr = (vu_short *)(info->start[sect]); | |
230 | + | |
231 | + MEM_FLASH_ADDR1 = CMD_UNLOCK1; | |
232 | + MEM_FLASH_ADDR2 = CMD_UNLOCK2; | |
233 | + MEM_FLASH_ADDR1 = CMD_ERASE_SETUP; | |
234 | + | |
235 | + MEM_FLASH_ADDR1 = CMD_UNLOCK1; | |
236 | + MEM_FLASH_ADDR2 = CMD_UNLOCK2; | |
237 | + *addr = CMD_ERASE_CONFIRM; | |
238 | + | |
239 | + /* wait until flash is ready */ | |
240 | + chip = 0; | |
241 | + | |
242 | + do | |
243 | + { | |
244 | + result = *addr; | |
245 | + | |
246 | + /* check timeout */ | |
247 | + if (get_timer_masked() > CFG_FLASH_ERASE_TOUT) | |
248 | + { | |
249 | + MEM_FLASH_ADDR1 = CMD_READ_ARRAY; | |
250 | + chip = TMO; | |
251 | + break; | |
252 | + } | |
253 | + | |
254 | + if (!chip && (result & 0xFFFF) & BIT_ERASE_DONE) | |
255 | + chip = READY; | |
256 | + | |
257 | + if (!chip && (result & 0xFFFF) & BIT_PROGRAM_ERROR) | |
258 | + chip = ERR; | |
259 | + | |
260 | + } while (!chip); | |
261 | + | |
262 | + MEM_FLASH_ADDR1 = CMD_READ_ARRAY; | |
263 | + | |
264 | + if (chip == ERR) | |
265 | + { | |
266 | + rc = ERR_PROG_ERROR; | |
267 | + goto outahere; | |
268 | + } | |
269 | + if (chip == TMO) | |
270 | + { | |
271 | + rc = ERR_TIMOUT; | |
272 | + goto outahere; | |
273 | + } | |
274 | + | |
275 | + printf("ok.\n"); | |
276 | + } | |
277 | + else /* it was protected */ | |
278 | + { | |
279 | + printf("protected!\n"); | |
280 | + } | |
281 | + } | |
282 | + | |
283 | + if (ctrlc()) | |
284 | + printf("User Interrupt!\n"); | |
285 | + | |
286 | +outahere: | |
287 | + /* allow flash to settle - wait 10 ms */ | |
288 | + udelay_masked(10000); | |
289 | + | |
290 | + if (iflag) | |
291 | + enable_interrupts(); | |
292 | + | |
293 | + if (cflag) | |
294 | + icache_enable(); | |
295 | + | |
296 | + return rc; | |
297 | +} | |
298 | + | |
299 | +/*----------------------------------------------------------------------- | |
300 | + * Copy memory to flash | |
301 | + */ | |
302 | + | |
303 | +volatile static int write_hword (flash_info_t *info, ulong dest, ushort data) | |
304 | +{ | |
305 | + vu_short *addr = (vu_short *)dest; | |
306 | + ushort result; | |
307 | + int rc = ERR_OK; | |
308 | + int cflag, iflag; | |
309 | + int chip; | |
310 | + | |
311 | + /* | |
312 | + * Check if Flash is (sufficiently) erased | |
313 | + */ | |
314 | + result = *addr; | |
315 | + if ((result & data) != data) | |
316 | + return ERR_NOT_ERASED; | |
317 | + | |
318 | + | |
319 | + /* | |
320 | + * Disable interrupts which might cause a timeout | |
321 | + * here. Remember that our exception vectors are | |
322 | + * at address 0 in the flash, and we don't want a | |
323 | + * (ticker) exception to happen while the flash | |
324 | + * chip is in programming mode. | |
325 | + */ | |
326 | + cflag = icache_status(); | |
327 | + icache_disable(); | |
328 | + iflag = disable_interrupts(); | |
329 | + | |
330 | + MEM_FLASH_ADDR1 = CMD_UNLOCK1; | |
331 | + MEM_FLASH_ADDR2 = CMD_UNLOCK2; | |
332 | + MEM_FLASH_ADDR1 = CMD_UNLOCK_BYPASS; | |
333 | + *addr = CMD_PROGRAM; | |
334 | + *addr = data; | |
335 | + | |
336 | + /* arm simple, non interrupt dependent timer */ | |
337 | + reset_timer_masked(); | |
338 | + | |
339 | + /* wait until flash is ready */ | |
340 | + chip = 0; | |
341 | + do | |
342 | + { | |
343 | + result = *addr; | |
344 | + | |
345 | + /* check timeout */ | |
346 | + if (get_timer_masked() > CFG_FLASH_ERASE_TOUT) | |
347 | + { | |
348 | + chip = ERR | TMO; | |
349 | + break; | |
350 | + } | |
351 | + if (!chip && ((result & 0x80) == (data & 0x80))) | |
352 | + chip = READY; | |
353 | + | |
354 | + if (!chip && ((result & 0xFFFF) & BIT_PROGRAM_ERROR)) | |
355 | + { | |
356 | + result = *addr; | |
357 | + | |
358 | + if ((result & 0x80) == (data & 0x80)) | |
359 | + chip = READY; | |
360 | + else | |
361 | + chip = ERR; | |
362 | + } | |
363 | + | |
364 | + } while (!chip); | |
365 | + | |
366 | + *addr = CMD_READ_ARRAY; | |
367 | + | |
368 | + if (chip == ERR || *addr != data) | |
369 | + rc = ERR_PROG_ERROR; | |
370 | + | |
371 | + if (iflag) | |
372 | + enable_interrupts(); | |
373 | + | |
374 | + if (cflag) | |
375 | + icache_enable(); | |
376 | + | |
377 | + return rc; | |
378 | +} | |
379 | + | |
380 | +/*----------------------------------------------------------------------- | |
381 | + * Copy memory to flash. | |
382 | + */ | |
383 | + | |
384 | +int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt) | |
385 | +{ | |
386 | + ulong cp, wp; | |
387 | + int l; | |
388 | + int i, rc; | |
389 | + ushort data; | |
390 | + | |
391 | + wp = (addr & ~1); /* get lower word aligned address */ | |
392 | + | |
393 | + /* | |
394 | + * handle unaligned start bytes | |
395 | + */ | |
396 | + if ((l = addr - wp) != 0) { | |
397 | + data = 0; | |
398 | + for (i=0, cp=wp; i<l; ++i, ++cp) { | |
399 | + data = (data >> 8) | (*(uchar *)cp << 8); | |
400 | + } | |
401 | + for (; i<2 && cnt>0; ++i) { | |
402 | + data = (data >> 8) | (*src++ << 8); | |
403 | + --cnt; | |
404 | + ++cp; | |
405 | + } | |
406 | + for (; cnt==0 && i<2; ++i, ++cp) { | |
407 | + data = (data >> 8) | (*(uchar *)cp << 8); | |
408 | + } | |
409 | + | |
410 | + if ((rc = write_hword(info, wp, data)) != 0) { | |
411 | + return (rc); | |
412 | + } | |
413 | + wp += 2; | |
414 | + } | |
415 | + | |
416 | + /* | |
417 | + * handle word aligned part | |
418 | + */ | |
419 | + while (cnt >= 2) { | |
420 | + data = *((vu_short*)src); | |
421 | + if ((rc = write_hword(info, wp, data)) != 0) { | |
422 | + return (rc); | |
423 | + } | |
424 | + src += 2; | |
425 | + wp += 2; | |
426 | + cnt -= 2; | |
427 | + } | |
428 | + | |
429 | + if (cnt == 0) { | |
430 | + return ERR_OK; | |
431 | + } | |
432 | + | |
433 | + /* | |
434 | + * handle unaligned tail bytes | |
435 | + */ | |
436 | + data = 0; | |
437 | + for (i=0, cp=wp; i<2 && cnt>0; ++i, ++cp) { | |
438 | + data = (data >> 8) | (*src++ << 8); | |
439 | + --cnt; | |
440 | + } | |
441 | + for (; i<2; ++i, ++cp) { | |
442 | + data = (data >> 8) | (*(uchar *)cp << 8); | |
443 | + } | |
444 | + | |
445 | + return write_hword(info, wp, data); | |
446 | +} |