]>
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 | ||
0060517a | 75 | /* cppcheck-suppress nullPointer */ |
281e00a3 WD |
76 | *addr = FLASH_CMD (CFI_INTEL_CMD_READ_STATUS_REGISTER); |
77 | ||
0060517a | 78 | /* cppcheck-suppress nullPointer */ |
281e00a3 WD |
79 | return *addr; |
80 | } | |
81 | ||
82 | static int flash_ready (ulong timeout) | |
83 | { | |
84 | int ok = 1; | |
a60d1e5b | 85 | ulong start; |
281e00a3 | 86 | |
a60d1e5b | 87 | start = get_timer(0); |
281e00a3 WD |
88 | while ((flash_status_reg () & FLASH_CMD (CFI_INTEL_SR_READY)) != |
89 | FLASH_CMD (CFI_INTEL_SR_READY)) { | |
a60d1e5b | 90 | if (get_timer(start) > timeout && timeout != 0) { |
281e00a3 WD |
91 | ok = 0; |
92 | break; | |
93 | } | |
94 | } | |
95 | return ok; | |
96 | } | |
97 | ||
6d0f6bcf | 98 | #if ( CONFIG_SYS_MAX_FLASH_BANKS != 1 ) |
281e00a3 WD |
99 | # error "SCB9328 platform has only one flash bank!" |
100 | #endif | |
101 | ||
102 | ||
103 | ulong flash_init (void) | |
104 | { | |
105 | int i; | |
106 | unsigned long address = SCB9328_FLASH_BASE; | |
107 | ||
108 | flash_info[0].size = SCB9328_FLASH_BANK_SIZE; | |
6d0f6bcf | 109 | flash_info[0].sector_count = CONFIG_SYS_MAX_FLASH_SECT; |
281e00a3 | 110 | flash_info[0].flash_id = INTEL_MANUFACT; |
6d0f6bcf | 111 | memset (flash_info[0].protect, 0, CONFIG_SYS_MAX_FLASH_SECT); |
281e00a3 | 112 | |
6d0f6bcf | 113 | for (i = 0; i < CONFIG_SYS_MAX_FLASH_SECT; i++) { |
281e00a3 WD |
114 | flash_info[0].start[i] = address; |
115 | #ifdef SCB9328_FLASH_UNLOCK | |
116 | /* Some devices are hw locked after start. */ | |
117 | *((FLASH_BUS *) address) = FLASH_CMD (CFI_INTEL_CMD_LOCK_SETUP); | |
118 | *((FLASH_BUS *) address) = FLASH_CMD (CFI_INTEL_CMD_UNLOCK_BLOCK); | |
119 | flash_ready (0); | |
120 | *((FLASH_BUS *) address) = FLASH_CMD (CFI_INTEL_CMD_READ_ARRAY); | |
121 | #endif | |
122 | address += SCB9328_FLASH_SECT_SIZE; | |
123 | } | |
124 | ||
125 | flash_protect (FLAG_PROTECT_SET, | |
6d0f6bcf JCPV |
126 | CONFIG_SYS_FLASH_BASE, |
127 | CONFIG_SYS_FLASH_BASE + monitor_flash_len - 1, | |
281e00a3 WD |
128 | &flash_info[0]); |
129 | ||
130 | flash_protect (FLAG_PROTECT_SET, | |
0e8d1586 JCPV |
131 | CONFIG_ENV_ADDR, |
132 | CONFIG_ENV_ADDR + CONFIG_ENV_SIZE - 1, &flash_info[0]); | |
281e00a3 WD |
133 | |
134 | return SCB9328_FLASH_BANK_SIZE; | |
135 | } | |
136 | ||
137 | void flash_print_info (flash_info_t * info) | |
138 | { | |
139 | int i; | |
140 | ||
141 | printf (" Intel vendor\n"); | |
142 | printf (" Size: %ld MB in %d Sectors\n", | |
143 | info->size >> 20, info->sector_count); | |
144 | ||
145 | printf (" Sector Start Addresses:"); | |
146 | for (i = 0; i < info->sector_count; i++) { | |
147 | if (!(i % 5)) { | |
148 | printf ("\n"); | |
149 | } | |
150 | ||
151 | printf (" %08lX%s", info->start[i], | |
152 | info->protect[i] ? " (RO)" : " "); | |
153 | } | |
154 | printf ("\n"); | |
155 | } | |
156 | ||
157 | ||
158 | int flash_erase (flash_info_t * info, int s_first, int s_last) | |
159 | { | |
160 | int flag, non_protected = 0, sector; | |
161 | int rc = ERR_OK; | |
162 | ||
163 | FLASH_BUS *address; | |
164 | ||
165 | for (sector = s_first; sector <= s_last; sector++) { | |
166 | if (!info->protect[sector]) { | |
167 | non_protected++; | |
168 | } | |
169 | } | |
170 | ||
171 | if (!non_protected) { | |
172 | return ERR_PROTECTED; | |
173 | } | |
174 | ||
175 | /* | |
176 | * Disable interrupts which might cause a timeout | |
177 | * here. Remember that our exception vectors are | |
178 | * at address 0 in the flash, and we don't want a | |
179 | * (ticker) exception to happen while the flash | |
180 | * chip is in programming mode. | |
181 | */ | |
182 | flag = disable_interrupts (); | |
183 | ||
184 | ||
185 | /* Start erase on unprotected sectors */ | |
186 | for (sector = s_first; sector <= s_last && !ctrlc (); sector++) { | |
187 | if (info->protect[sector]) { | |
188 | printf ("Protected sector %2d skipping...\n", sector); | |
189 | continue; | |
190 | } else { | |
191 | printf ("Erasing sector %2d ... ", sector); | |
192 | } | |
193 | ||
194 | address = (FLASH_BUS *) (info->start[sector]); | |
195 | ||
196 | *address = FLASH_CMD (CFI_INTEL_CMD_BLOCK_ERASE); | |
197 | *address = FLASH_CMD (CFI_INTEL_CMD_CONFIRM); | |
6d0f6bcf | 198 | if (flash_ready (CONFIG_SYS_FLASH_ERASE_TOUT)) { |
281e00a3 WD |
199 | *address = FLASH_CMD (CFI_INTEL_CMD_CLEAR_STATUS_REGISTER); |
200 | printf ("ok.\n"); | |
201 | } else { | |
202 | *address = FLASH_CMD (CFI_INTEL_CMD_SUSPEND); | |
203 | rc = ERR_TIMOUT; | |
204 | printf ("timeout! Aborting...\n"); | |
205 | break; | |
206 | } | |
207 | *address = FLASH_CMD (CFI_INTEL_CMD_READ_ARRAY); | |
208 | } | |
209 | if (ctrlc ()) | |
210 | printf ("User Interrupt!\n"); | |
211 | ||
212 | /* allow flash to settle - wait 10 ms */ | |
213 | udelay_masked (10000); | |
214 | if (flag) { | |
215 | enable_interrupts (); | |
216 | } | |
217 | ||
218 | return rc; | |
219 | } | |
220 | ||
221 | static int write_data (flash_info_t * info, ulong dest, FLASH_BUS data) | |
222 | { | |
223 | FLASH_BUS *address = (FLASH_BUS *) dest; | |
224 | int rc = ERR_OK; | |
225 | int flag; | |
226 | ||
227 | /* Check if Flash is (sufficiently) erased */ | |
228 | if ((*address & data) != data) { | |
229 | return ERR_NOT_ERASED; | |
230 | } | |
231 | ||
232 | /* | |
233 | * Disable interrupts which might cause a timeout | |
234 | * here. Remember that our exception vectors are | |
235 | * at address 0 in the flash, and we don't want a | |
236 | * (ticker) exception to happen while the flash | |
237 | * chip is in programming mode. | |
238 | */ | |
239 | ||
240 | flag = disable_interrupts (); | |
241 | ||
242 | *address = FLASH_CMD (CFI_INTEL_CMD_CLEAR_STATUS_REGISTER); | |
243 | *address = FLASH_CMD (CFI_INTEL_CMD_PROGRAM1); | |
244 | *address = data; | |
245 | ||
6d0f6bcf | 246 | if (!flash_ready (CONFIG_SYS_FLASH_WRITE_TOUT)) { |
281e00a3 WD |
247 | *address = FLASH_CMD (CFI_INTEL_CMD_SUSPEND); |
248 | rc = ERR_TIMOUT; | |
249 | printf ("timeout! Aborting...\n"); | |
250 | } | |
251 | ||
252 | *address = FLASH_CMD (CFI_INTEL_CMD_READ_ARRAY); | |
253 | if (flag) { | |
254 | enable_interrupts (); | |
255 | } | |
256 | ||
257 | return rc; | |
258 | } | |
259 | ||
260 | int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt) | |
261 | { | |
262 | ulong read_addr, write_addr; | |
263 | FLASH_BUS data; | |
264 | int i, result = ERR_OK; | |
265 | ||
266 | ||
267 | read_addr = addr & ~(sizeof (FLASH_BUS) - 1); | |
268 | write_addr = read_addr; | |
269 | if (read_addr != addr) { | |
270 | data = 0; | |
271 | for (i = 0; i < sizeof (FLASH_BUS); i++) { | |
272 | if (read_addr < addr || cnt == 0) { | |
273 | data |= *((uchar *) read_addr) << i * 8; | |
274 | } else { | |
275 | data |= (*src++) << i * 8; | |
276 | cnt--; | |
277 | } | |
278 | read_addr++; | |
279 | } | |
280 | if ((result = write_data (info, write_addr, data)) != ERR_OK) { | |
281 | return result; | |
282 | } | |
283 | write_addr += sizeof (FLASH_BUS); | |
284 | } | |
285 | for (; cnt >= sizeof (FLASH_BUS); cnt -= sizeof (FLASH_BUS)) { | |
286 | if ((result = write_data (info, write_addr, | |
287 | *((FLASH_BUS *) src))) != ERR_OK) { | |
288 | return result; | |
289 | } | |
290 | write_addr += sizeof (FLASH_BUS); | |
291 | src += sizeof (FLASH_BUS); | |
292 | } | |
293 | if (cnt > 0) { | |
294 | read_addr = write_addr; | |
295 | data = 0; | |
296 | for (i = 0; i < sizeof (FLASH_BUS); i++) { | |
297 | if (cnt > 0) { | |
298 | data |= (*src++) << i * 8; | |
299 | cnt--; | |
300 | } else { | |
301 | data |= *((uchar *) read_addr) << i * 8; | |
302 | } | |
303 | read_addr++; | |
304 | } | |
305 | if ((result = write_data (info, write_addr, data)) != 0) { | |
306 | return result; | |
307 | } | |
308 | } | |
309 | return ERR_OK; | |
310 | } |