]>
Commit | Line | Data |
---|---|---|
c570b2fd WD |
1 | /* |
2 | * (C) Copyright 2002 | |
3 | * Sysgo Real-Time Solutions, GmbH <www.elinos.com> | |
4 | * Marius Groeger <mgroeger@sysgo.de> | |
5 | * | |
6 | * (C) Copyright 2005 Rowel Atienza <rowel@diwalabs.com> | |
7 | * Flash driver for armadillo board HT1070 | |
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 | ||
32 | /*value used by hermit is 0x200*/ | |
33 | /*document says sector size is either 64k in low mem reg and 8k in high mem reg*/ | |
34 | #define MAIN_SECT_SIZE 0x10000 | |
35 | ||
36 | #define UNALIGNED_MASK (3) | |
37 | #define FL_WORD(addr) (*(volatile unsigned short*)(addr)) | |
38 | #define FLASH_TIMEOUT 20000000 | |
39 | ||
6d0f6bcf | 40 | flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS]; |
c570b2fd WD |
41 | |
42 | /*----------------------------------------------------------------------- | |
43 | */ | |
44 | ||
45 | ulong flash_init (void) | |
46 | { | |
47 | int i, j; | |
48 | ulong size = 0; | |
49 | ||
6d0f6bcf | 50 | for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) { |
c570b2fd WD |
51 | ulong flashbase = 0; |
52 | ||
53 | flash_info[i].flash_id = (FUJ_MANUFACT & FLASH_VENDMASK); | |
54 | /*(INTEL_ID_28F128J3 & FLASH_TYPEMASK); */ | |
55 | flash_info[i].size = FLASH_BANK_SIZE; | |
6d0f6bcf JCPV |
56 | flash_info[i].sector_count = CONFIG_SYS_MAX_FLASH_SECT; |
57 | memset (flash_info[i].protect, 0, CONFIG_SYS_MAX_FLASH_SECT); | |
c570b2fd WD |
58 | if (i == 0) |
59 | flashbase = PHYS_FLASH_1; | |
60 | else | |
61 | panic ("configured too many flash banks!\n"); | |
62 | for (j = 0; j < flash_info[i].sector_count; j++) { | |
63 | flash_info[i].start[j] = | |
64 | flashbase + j * MAIN_SECT_SIZE; | |
65 | } | |
66 | size += flash_info[i].size; | |
67 | } | |
68 | ||
69 | /* Protect monitor and environment sectors | |
70 | */ | |
71 | flash_protect (FLAG_PROTECT_SET, | |
6d0f6bcf JCPV |
72 | CONFIG_SYS_FLASH_BASE, |
73 | CONFIG_SYS_FLASH_BASE + monitor_flash_len - 1, | |
c570b2fd WD |
74 | &flash_info[0]); |
75 | ||
76 | flash_protect (FLAG_PROTECT_SET, | |
0e8d1586 JCPV |
77 | CONFIG_ENV_ADDR, |
78 | CONFIG_ENV_ADDR + CONFIG_ENV_SIZE - 1, &flash_info[0]); | |
c570b2fd WD |
79 | |
80 | return size; | |
81 | } | |
82 | ||
83 | /*----------------------------------------------------------------------- | |
84 | */ | |
85 | void flash_print_info (flash_info_t * info) | |
86 | { | |
87 | int i; | |
88 | ||
89 | switch (info->flash_id & FLASH_VENDMASK) { | |
90 | case (FUJ_MANUFACT & FLASH_VENDMASK): | |
91 | printf ("Fujitsu: "); | |
92 | break; | |
93 | default: | |
94 | printf ("Unknown Vendor "); | |
95 | break; | |
96 | } | |
97 | /* | |
98 | switch (info->flash_id & FLASH_TYPEMASK) { | |
99 | case (INTEL_ID_28F128J3 & FLASH_TYPEMASK): | |
100 | printf ("28F128J3 (128Mbit)\n"); | |
101 | break; | |
102 | default: | |
103 | printf ("Unknown Chip Type\n"); | |
104 | goto Done; | |
105 | break; | |
106 | } | |
107 | */ | |
108 | printf (" Size: %ld MB in %d Sectors\n", | |
109 | info->size >> 20, info->sector_count); | |
110 | ||
111 | printf (" Sector Start Addresses:"); | |
112 | for (i = 0; i < info->sector_count; i++) { | |
113 | if ((i % 5) == 0) { | |
114 | printf ("\n "); | |
115 | } | |
116 | printf (" %08lX%s", info->start[i], | |
117 | info->protect[i] ? " (RO)" : " "); | |
118 | } | |
119 | printf ("\n"); | |
120 | ||
b8e16a34 WD |
121 | /* |
122 | Done: ; | |
123 | */ | |
c570b2fd WD |
124 | } |
125 | ||
126 | /* | |
127 | * * Loop until both write state machines complete. | |
128 | * */ | |
129 | static unsigned short flash_status_wait (unsigned long addr, | |
130 | unsigned short value) | |
131 | { | |
132 | unsigned short status; | |
133 | long timeout = FLASH_TIMEOUT; | |
134 | ||
135 | while (((status = (FL_WORD (addr))) != value) && timeout > 0) { | |
136 | timeout--; | |
137 | } | |
138 | return status; | |
139 | } | |
140 | ||
141 | /* | |
142 | * Loop until the Write State machine is ready, then do a full error | |
143 | * check. Clear status and leave the flash in Read Array mode; return | |
144 | * 0 for no error, -1 for error. | |
145 | */ | |
146 | static int flash_status_full_check (unsigned long addr, unsigned short value1, | |
147 | unsigned short value2) | |
148 | { | |
149 | unsigned short status1, status2; | |
150 | ||
151 | status1 = flash_status_wait (addr, value1); | |
152 | status2 = flash_status_wait (addr + 2, value2); | |
153 | return (status1 != value1 || status2 != value2) ? -1 : 0; | |
154 | } | |
155 | ||
156 | /*----------------------------------------------------------------------- | |
157 | */ | |
158 | ||
159 | int flash_erase (flash_info_t * info, int s_first, int s_last) | |
160 | { | |
161 | int flag, prot, sect; | |
162 | int rc = ERR_OK; | |
163 | unsigned long base; | |
164 | unsigned long addr; | |
165 | ||
166 | if ((info->flash_id & FLASH_VENDMASK) != | |
167 | (FUJ_MANUFACT & FLASH_VENDMASK)) { | |
168 | return ERR_UNKNOWN_FLASH_VENDOR; | |
169 | } | |
170 | ||
171 | prot = 0; | |
172 | for (sect = s_first; sect <= s_last; ++sect) { | |
173 | if (info->protect[sect]) { | |
174 | prot++; | |
175 | } | |
176 | } | |
177 | if (prot) | |
178 | return ERR_PROTECTED; | |
179 | ||
180 | /* | |
181 | * Disable interrupts which might cause a timeout | |
182 | * here. Remember that our exception vectors are | |
183 | * at address 0 in the flash, and we don't want a | |
184 | * (ticker) exception to happen while the flash | |
185 | * chip is in programming mode. | |
186 | */ | |
187 | flag = disable_interrupts (); | |
188 | ||
189 | printf ("Erasing %d sectors starting at sector %2d.\n" | |
190 | "This make take some time ... ", | |
191 | s_last - s_first, sect); | |
192 | /* Start erase on unprotected sectors */ | |
193 | for (sect = s_first; sect <= s_last && !ctrlc (); sect++) { | |
194 | /* ARM simple, non interrupt dependent timer */ | |
195 | reset_timer_masked (); | |
196 | ||
197 | if (info->protect[sect] == 0) { /* not protected */ | |
198 | ||
199 | addr = sect * MAIN_SECT_SIZE; | |
200 | addr &= ~(unsigned long) UNALIGNED_MASK; /* word align */ | |
201 | base = addr & 0xF0000000; | |
202 | ||
203 | FL_WORD (base + (0x555 << 1)) = 0xAA; | |
204 | FL_WORD (base + (0x2AA << 1)) = 0x55; | |
205 | FL_WORD (base + (0x555 << 1)) = 0x80; | |
206 | FL_WORD (base + (0x555 << 1)) = 0xAA; | |
207 | FL_WORD (base + (0x2AA << 1)) = 0x55; | |
208 | FL_WORD (addr) = 0x30; | |
209 | if (flash_status_full_check (addr, 0xFFFF, 0xFFFF)) | |
210 | return ERR_PROTECTED; | |
211 | } | |
212 | } | |
213 | printf ("\nDone.\n"); | |
214 | if (ctrlc ()) | |
215 | printf ("User Interrupt!\n"); | |
216 | ||
217 | /* allow flash to settle - wait 10 ms */ | |
218 | udelay_masked (10000); | |
219 | ||
220 | if (flag) | |
221 | enable_interrupts (); | |
222 | ||
223 | return rc; | |
224 | } | |
225 | ||
226 | ||
227 | /*----------------------------------------------------------------------- | |
228 | * Copy memory to flash | |
229 | */ | |
230 | ||
231 | static int write_word (flash_info_t * info, ulong dest, ushort data) | |
232 | { | |
233 | int flag; | |
234 | unsigned long base; | |
235 | ||
236 | /* Check if Flash is (sufficiently) erased | |
237 | */ | |
238 | if ((FL_WORD (dest) & data) != data) | |
239 | return ERR_NOT_ERASED; | |
240 | ||
241 | /*if(dest & UNALIGNED_MASK) return ERR_ALIGN; */ | |
242 | ||
243 | /* | |
244 | * Disable interrupts which might cause a timeout | |
245 | * here. Remember that our exception vectors are | |
246 | * at address 0 in the flash, and we don't want a | |
247 | * (ticker) exception to happen while the flash | |
248 | * chip is in programming mode. | |
249 | */ | |
250 | flag = disable_interrupts (); | |
251 | ||
252 | /* arm simple, non interrupt dependent timer */ | |
253 | reset_timer_masked (); | |
254 | ||
255 | base = dest & 0xF0000000; | |
256 | FL_WORD (base + (0x555 << 1)) = 0xAA; | |
257 | FL_WORD (base + (0x2AA << 1)) = 0x55; | |
258 | FL_WORD (base + (0x555 << 1)) = 0xA0; | |
259 | FL_WORD (dest) = data; | |
260 | /*printf("writing 0x%p = 0x%x\n",dest,data); */ | |
261 | if (flash_status_wait (dest, data) != data) | |
262 | return ERR_PROG_ERROR; | |
263 | ||
264 | if (flag) | |
265 | enable_interrupts (); | |
266 | ||
267 | return ERR_OK; | |
268 | } | |
269 | ||
270 | /*----------------------------------------------------------------------- | |
271 | * Copy memory to flash. | |
272 | */ | |
273 | ||
274 | int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt) | |
275 | { | |
276 | ulong cp, wp; | |
277 | ushort data; | |
278 | int l; | |
279 | int i, rc; | |
280 | ||
281 | wp = (addr & ~1); /* get lower word aligned address */ | |
0a5676be | 282 | printf ("Writing %lu short data to 0x%lx from 0x%p.\n ", cnt, wp, src); |
c570b2fd WD |
283 | |
284 | /* | |
285 | * handle unaligned start bytes | |
286 | */ | |
287 | if ((l = addr - wp) != 0) { | |
288 | data = 0; | |
289 | for (i = 0, cp = wp; i < l; ++i, ++cp) { | |
290 | data = (data >> 8) | (*(uchar *) cp << 8); | |
291 | } | |
292 | for (; i < 2 && cnt > 0; ++i) { | |
293 | data = (data >> 8) | (*src++ << 8); | |
294 | --cnt; | |
295 | ++cp; | |
296 | } | |
297 | for (; cnt == 0 && i < 2; ++i, ++cp) { | |
298 | data = (data >> 8) | (*(uchar *) cp << 8); | |
299 | } | |
300 | ||
301 | if ((rc = write_word (info, wp, data)) != 0) { | |
302 | return (rc); | |
303 | } | |
304 | wp += 2; | |
305 | } | |
306 | ||
307 | /* | |
308 | * handle word aligned part | |
309 | */ | |
310 | while (cnt >= 2) { | |
311 | data = *((vu_short *) src); | |
312 | if ((rc = write_word (info, wp, data)) != 0) { | |
313 | return (rc); | |
314 | } | |
315 | src += 2; | |
316 | wp += 2; | |
317 | cnt -= 2; | |
318 | } | |
319 | ||
320 | if (cnt == 0) { | |
321 | printf ("\nDone.\n"); | |
322 | return ERR_OK; | |
323 | } | |
324 | ||
325 | /* | |
326 | * handle unaligned tail bytes | |
327 | */ | |
328 | data = 0; | |
329 | for (i = 0, cp = wp; i < 2 && cnt > 0; ++i, ++cp) { | |
330 | data = (data >> 8) | (*src++ << 8); | |
331 | --cnt; | |
332 | } | |
333 | for (; i < 2; ++i, ++cp) { | |
334 | data = (data >> 8) | (*(uchar *) cp << 8); | |
335 | } | |
336 | ||
337 | return write_word (info, wp, data); | |
338 | } |