]>
Commit | Line | Data |
---|---|---|
43d9616c WD |
1 | /* |
2 | * (C) Copyright 2002 | |
3 | * Kyle Harris, Nexus Technologies, Inc. [email protected] | |
4 | * | |
5 | * (C) Copyright 2002 | |
6 | * Sysgo Real-Time Solutions, GmbH <www.elinos.com> | |
7 | * Marius Groeger <[email protected]> | |
8 | * | |
9 | * (C) Copyright 2002 | |
10 | * Robert Schwebel, Pengutronix, <[email protected]> | |
11 | * | |
dc7c9a1a | 12 | * (C) Copyright 2002 |
8bde7f77 | 13 | * Auerswald GmbH & Co KG, Germany |
3e38691e | 14 | * Kai-Uwe Bloem <[email protected]> |
dc7c9a1a | 15 | * |
43d9616c WD |
16 | * See file CREDITS for list of people who contributed to this |
17 | * project. | |
18 | * | |
19 | * This program is free software; you can redistribute it and/or | |
20 | * modify it under the terms of the GNU General Public License as | |
21 | * published by the Free Software Foundation; either version 2 of | |
22 | * the License, or (at your option) any later version. | |
23 | * | |
24 | * This program is distributed in the hope that it will be useful, | |
25 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
26 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
27 | * GNU General Public License for more details. | |
28 | * | |
29 | * You should have received a copy of the GNU General Public License | |
30 | * along with this program; if not, write to the Free Software | |
31 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
32 | * MA 02111-1307 USA | |
33 | */ | |
34 | ||
35 | #include <common.h> | |
36 | #include <asm/arch/pxa-regs.h> | |
37 | ||
47cd00fa WD |
38 | /* Debugging macros ------------------------------------------------------ */ |
39 | ||
40 | #undef FLASH_DEBUG | |
47cd00fa WD |
41 | |
42 | /* Some debug macros */ | |
43 | #if (FLASH_DEBUG > 2 ) | |
44 | #define PRINTK3(args...) printf(args) | |
45 | #else | |
46 | #define PRINTK3(args...) | |
47 | #endif | |
48 | ||
49 | #if FLASH_DEBUG > 1 | |
50 | #define PRINTK2(args...) printf(args) | |
51 | #else | |
52 | #define PRINTK2(args...) | |
53 | #endif | |
54 | ||
55 | #ifdef FLASH_DEBUG | |
56 | #define PRINTK(args...) printf(args) | |
57 | #else | |
58 | #define PRINTK(args...) | |
59 | #endif | |
60 | ||
61 | /* ------------------------------------------------------------------------ */ | |
62 | ||
63 | /* Development system: we have only 16 MB Flash */ | |
64 | #ifdef CONFIG_MTD_INNOKOM_16MB | |
65 | #define FLASH_BANK_SIZE 0x01000000 /* 16 MB (during development) */ | |
66 | #define MAIN_SECT_SIZE 0x00020000 /* 128k per sector */ | |
67 | #endif | |
68 | ||
69 | /* Production system: we have 64 MB Flash */ | |
70 | #ifdef CONFIG_MTD_INNOKOM_64MB | |
71 | #define FLASH_BANK_SIZE 0x04000000 /* 64 MB */ | |
72 | #define MAIN_SECT_SIZE 0x00020000 /* 128k per sector */ | |
73 | #endif | |
43d9616c | 74 | |
6d0f6bcf | 75 | flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS]; |
43d9616c | 76 | |
43d9616c WD |
77 | /** |
78 | * flash_init: - initialize data structures for flash chips | |
79 | * | |
80 | * @return: size of the flash | |
81 | */ | |
82 | ||
83 | ulong flash_init(void) | |
84 | { | |
85 | int i, j; | |
86 | ulong size = 0; | |
87 | ||
6d0f6bcf | 88 | for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) { |
43d9616c WD |
89 | ulong flashbase = 0; |
90 | flash_info[i].flash_id = | |
53677ef1 WD |
91 | (INTEL_MANUFACT & FLASH_VENDMASK) | |
92 | (INTEL_ID_28F128J3 & FLASH_TYPEMASK); | |
43d9616c | 93 | flash_info[i].size = FLASH_BANK_SIZE; |
6d0f6bcf JCPV |
94 | flash_info[i].sector_count = CONFIG_SYS_MAX_FLASH_SECT; |
95 | memset(flash_info[i].protect, 0, CONFIG_SYS_MAX_FLASH_SECT); | |
43d9616c WD |
96 | |
97 | switch (i) { | |
98 | case 0: | |
99 | flashbase = PHYS_FLASH_1; | |
100 | break; | |
101 | default: | |
5f535fe1 | 102 | panic("configured too many flash banks!\n"); |
43d9616c WD |
103 | break; |
104 | } | |
105 | for (j = 0; j < flash_info[i].sector_count; j++) { | |
106 | flash_info[i].start[j] = flashbase + j*MAIN_SECT_SIZE; | |
107 | } | |
108 | size += flash_info[i].size; | |
109 | } | |
110 | ||
47cd00fa | 111 | /* Protect u-boot sectors */ |
43d9616c | 112 | flash_protect(FLAG_PROTECT_SET, |
6d0f6bcf JCPV |
113 | CONFIG_SYS_FLASH_BASE, |
114 | CONFIG_SYS_FLASH_BASE + (256*1024) - 1, | |
43d9616c WD |
115 | &flash_info[0]); |
116 | ||
5a1aceb0 | 117 | #ifdef CONFIG_ENV_IS_IN_FLASH |
43d9616c | 118 | flash_protect(FLAG_PROTECT_SET, |
0e8d1586 JCPV |
119 | CONFIG_ENV_ADDR, |
120 | CONFIG_ENV_ADDR + CONFIG_ENV_SIZE - 1, | |
43d9616c WD |
121 | &flash_info[0]); |
122 | #endif | |
123 | ||
124 | return size; | |
125 | } | |
126 | ||
127 | ||
128 | /** | |
129 | * flash_print_info: - print information about the flash situation | |
130 | * | |
131 | * @param info: | |
132 | */ | |
133 | ||
134 | void flash_print_info (flash_info_t *info) | |
135 | { | |
136 | int i, j; | |
137 | ||
6d0f6bcf | 138 | for (j=0; j<CONFIG_SYS_MAX_FLASH_BANKS; j++) { |
43d9616c WD |
139 | |
140 | switch (info->flash_id & FLASH_VENDMASK) { | |
141 | ||
142 | case (INTEL_MANUFACT & FLASH_VENDMASK): | |
143 | printf("Intel: "); | |
144 | break; | |
145 | default: | |
146 | printf("Unknown Vendor "); | |
147 | break; | |
148 | } | |
149 | ||
150 | switch (info->flash_id & FLASH_TYPEMASK) { | |
151 | ||
152 | case (INTEL_ID_28F128J3 & FLASH_TYPEMASK): | |
153 | printf("28F128J3 (128Mbit)\n"); | |
154 | break; | |
155 | default: | |
156 | printf("Unknown Chip Type\n"); | |
157 | return; | |
158 | } | |
159 | ||
8bde7f77 | 160 | printf(" Size: %ld MB in %d Sectors\n", |
43d9616c WD |
161 | info->size >> 20, info->sector_count); |
162 | ||
163 | printf(" Sector Start Addresses:"); | |
164 | for (i = 0; i < info->sector_count; i++) { | |
165 | if ((i % 5) == 0) printf ("\n "); | |
8bde7f77 | 166 | |
43d9616c WD |
167 | printf (" %08lX%s", info->start[i], |
168 | info->protect[i] ? " (RO)" : " "); | |
169 | } | |
170 | printf ("\n"); | |
171 | info++; | |
172 | } | |
173 | } | |
174 | ||
175 | ||
176 | /** | |
177 | * flash_erase: - erase flash sectors | |
178 | * | |
179 | */ | |
180 | ||
181 | int flash_erase(flash_info_t *info, int s_first, int s_last) | |
182 | { | |
183 | int flag, prot, sect; | |
184 | int rc = ERR_OK; | |
185 | ||
186 | if (info->flash_id == FLASH_UNKNOWN) | |
187 | return ERR_UNKNOWN_FLASH_TYPE; | |
188 | ||
189 | if ((s_first < 0) || (s_first > s_last)) { | |
190 | return ERR_INVAL; | |
191 | } | |
192 | ||
193 | if ((info->flash_id & FLASH_VENDMASK) != (INTEL_MANUFACT & FLASH_VENDMASK)) | |
194 | return ERR_UNKNOWN_FLASH_VENDOR; | |
8bde7f77 | 195 | |
43d9616c WD |
196 | prot = 0; |
197 | for (sect=s_first; sect<=s_last; ++sect) { | |
198 | if (info->protect[sect]) prot++; | |
199 | } | |
200 | ||
201 | if (prot) return ERR_PROTECTED; | |
202 | ||
203 | /* | |
204 | * Disable interrupts which might cause a timeout | |
205 | * here. Remember that our exception vectors are | |
206 | * at address 0 in the flash, and we don't want a | |
207 | * (ticker) exception to happen while the flash | |
208 | * chip is in programming mode. | |
209 | */ | |
210 | ||
211 | flag = disable_interrupts(); | |
212 | ||
213 | /* Start erase on unprotected sectors */ | |
214 | for (sect = s_first; sect<=s_last && !ctrlc(); sect++) { | |
215 | ||
216 | printf("Erasing sector %2d ... ", sect); | |
217 | ||
47cd00fa WD |
218 | PRINTK("\n"); |
219 | ||
43d9616c WD |
220 | /* arm simple, non interrupt dependent timer */ |
221 | reset_timer_masked(); | |
222 | ||
223 | if (info->protect[sect] == 0) { /* not protected */ | |
47cd00fa | 224 | u16 * volatile addr = (u16 * volatile)(info->start[sect]); |
43d9616c | 225 | |
47cd00fa WD |
226 | PRINTK("unlocking sector\n"); |
227 | *addr = 0x0060; | |
228 | *addr = 0x00d0; | |
229 | *addr = 0x00ff; | |
43d9616c | 230 | |
47cd00fa WD |
231 | PRINTK("erasing sector\n"); |
232 | *addr = 0x0020; | |
233 | PRINTK("confirming erase\n"); | |
234 | *addr = 0x00D0; | |
43d9616c | 235 | |
47cd00fa WD |
236 | while ((*addr & 0x0080) != 0x0080) { |
237 | PRINTK("."); | |
6d0f6bcf | 238 | if (get_timer_masked() > CONFIG_SYS_FLASH_ERASE_TOUT) { |
47cd00fa WD |
239 | *addr = 0x00B0; /* suspend erase*/ |
240 | *addr = 0x00FF; /* read mode */ | |
43d9616c WD |
241 | rc = ERR_TIMOUT; |
242 | goto outahere; | |
243 | } | |
244 | } | |
8bde7f77 | 245 | |
47cd00fa | 246 | PRINTK("clearing status register\n"); |
8bde7f77 | 247 | *addr = 0x0050; |
47cd00fa | 248 | PRINTK("resetting to read mode"); |
8bde7f77 | 249 | *addr = 0x00FF; |
43d9616c | 250 | } |
8bde7f77 | 251 | |
43d9616c WD |
252 | printf("ok.\n"); |
253 | } | |
254 | ||
255 | if (ctrlc()) printf("User Interrupt!\n"); | |
256 | ||
257 | outahere: | |
258 | ||
259 | /* allow flash to settle - wait 10 ms */ | |
260 | udelay_masked(10000); | |
261 | ||
262 | if (flag) enable_interrupts(); | |
263 | ||
264 | return rc; | |
265 | } | |
266 | ||
267 | ||
268 | /** | |
269 | * write_word: - copy memory to flash | |
270 | * | |
271 | * @param info: | |
272 | * @param dest: | |
273 | * @param data: | |
274 | * @return: | |
275 | */ | |
276 | ||
277 | static int write_word (flash_info_t *info, ulong dest, ushort data) | |
278 | { | |
47cd00fa | 279 | volatile u16 *addr = (u16 *)dest, val; |
43d9616c WD |
280 | int rc = ERR_OK; |
281 | int flag; | |
282 | ||
283 | /* Check if Flash is (sufficiently) erased */ | |
284 | if ((*addr & data) != data) return ERR_NOT_ERASED; | |
285 | ||
286 | /* | |
287 | * Disable interrupts which might cause a timeout | |
288 | * here. Remember that our exception vectors are | |
289 | * at address 0 in the flash, and we don't want a | |
290 | * (ticker) exception to happen while the flash | |
291 | * chip is in programming mode. | |
292 | */ | |
293 | flag = disable_interrupts(); | |
294 | ||
295 | /* clear status register command */ | |
296 | *addr = 0x50; | |
297 | ||
298 | /* program set-up command */ | |
299 | *addr = 0x40; | |
300 | ||
301 | /* latch address/data */ | |
302 | *addr = data; | |
303 | ||
304 | /* arm simple, non interrupt dependent timer */ | |
305 | reset_timer_masked(); | |
306 | ||
307 | /* wait while polling the status register */ | |
308 | while(((val = *addr) & 0x80) != 0x80) { | |
6d0f6bcf | 309 | if (get_timer_masked() > CONFIG_SYS_FLASH_WRITE_TOUT) { |
43d9616c WD |
310 | rc = ERR_TIMOUT; |
311 | *addr = 0xB0; /* suspend program command */ | |
312 | goto outahere; | |
313 | } | |
314 | } | |
315 | ||
316 | if(val & 0x1A) { /* check for error */ | |
317 | printf("\nFlash write error %02x at address %08lx\n", | |
318 | (int)val, (unsigned long)dest); | |
319 | if(val & (1<<3)) { | |
320 | printf("Voltage range error.\n"); | |
321 | rc = ERR_PROG_ERROR; | |
322 | goto outahere; | |
323 | } | |
324 | if(val & (1<<1)) { | |
325 | printf("Device protect error.\n"); | |
326 | rc = ERR_PROTECTED; | |
327 | goto outahere; | |
328 | } | |
329 | if(val & (1<<4)) { | |
330 | printf("Programming error.\n"); | |
331 | rc = ERR_PROG_ERROR; | |
332 | goto outahere; | |
333 | } | |
334 | rc = ERR_PROG_ERROR; | |
335 | goto outahere; | |
336 | } | |
337 | ||
338 | outahere: | |
339 | ||
340 | *addr = 0xFF; /* read array command */ | |
341 | if (flag) enable_interrupts(); | |
342 | ||
343 | return rc; | |
344 | } | |
345 | ||
346 | ||
347 | /** | |
348 | * write_buf: - Copy memory to flash. | |
349 | * | |
350 | * @param info: | |
351 | * @param src: source of copy transaction | |
352 | * @param addr: where to copy to | |
53677ef1 | 353 | * @param cnt: number of bytes to copy |
43d9616c WD |
354 | * |
355 | * @return error code | |
356 | */ | |
357 | ||
358 | int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt) | |
359 | { | |
360 | ulong cp, wp; | |
361 | ushort data; | |
362 | int l; | |
363 | int i, rc; | |
364 | ||
365 | wp = (addr & ~1); /* get lower word aligned address */ | |
366 | ||
367 | /* | |
368 | * handle unaligned start bytes | |
369 | */ | |
370 | if ((l = addr - wp) != 0) { | |
371 | data = 0; | |
372 | for (i=0, cp=wp; i<l; ++i, ++cp) { | |
373 | data = (data >> 8) | (*(uchar *)cp << 8); | |
374 | } | |
375 | for (; i<2 && cnt>0; ++i) { | |
376 | data = (data >> 8) | (*src++ << 8); | |
377 | --cnt; | |
378 | ++cp; | |
379 | } | |
380 | for (; cnt==0 && i<2; ++i, ++cp) { | |
381 | data = (data >> 8) | (*(uchar *)cp << 8); | |
382 | } | |
383 | ||
384 | if ((rc = write_word(info, wp, data)) != 0) { | |
385 | return (rc); | |
386 | } | |
387 | wp += 2; | |
388 | } | |
389 | ||
390 | /* | |
391 | * handle word aligned part | |
392 | */ | |
393 | while (cnt >= 2) { | |
394 | /* data = *((vushort*)src); */ | |
395 | data = *((ushort*)src); | |
396 | if ((rc = write_word(info, wp, data)) != 0) { | |
397 | return (rc); | |
398 | } | |
399 | src += 2; | |
400 | wp += 2; | |
401 | cnt -= 2; | |
402 | } | |
403 | ||
404 | if (cnt == 0) return ERR_OK; | |
405 | ||
406 | /* | |
407 | * handle unaligned tail bytes | |
408 | */ | |
409 | data = 0; | |
410 | for (i=0, cp=wp; i<2 && cnt>0; ++i, ++cp) { | |
411 | data = (data >> 8) | (*src++ << 8); | |
412 | --cnt; | |
413 | } | |
414 | for (; i<2; ++i, ++cp) { | |
415 | data = (data >> 8) | (*(uchar *)cp << 8); | |
416 | } | |
417 | ||
418 | return write_word(info, wp, data); | |
419 | } |