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