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