blob: 37326d587a66c9d32a4a2738eeb80251a5c3e6a4 [file] [log] [blame]
wdenkaffae2b2002-08-17 09:36:01 +00001/*
2 * (C) Copyright 2000
3 * Marius Groeger <mgroeger@sysgo.de>
4 * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
5 *
6 * (C) Copyright 2000
7 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
8 *
9 * Flash Routines for AM290[48]0B devices
10 *
11 *--------------------------------------------------------------------
Wolfgang Denk1a459662013-07-08 09:37:19 +020012 * SPDX-License-Identifier: GPL-2.0+
wdenkaffae2b2002-08-17 09:36:01 +000013 */
14
15#include <common.h>
16#include <mpc8xx.h>
17
18/* flash hardware ids */
19#define VENDOR_AMD 0x0001
20#define AMD_29DL323C_B 0x2253
21
22/* Define this to include autoselect sequence in flash_init(). Does NOT
23 * work when executing from flash itself, so this should be turned
24 * on only when debugging the RAM version.
25 */
26#undef WITH_AUTOSELECT
27
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020028flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS]; /* info for FLASH chips */
wdenkaffae2b2002-08-17 09:36:01 +000029
30#if 1
31#define D(x)
32#else
33#define D(x) printf x
34#endif
35
36/*-----------------------------------------------------------------------
37 * Functions
38 */
39
40static unsigned char write_ull(flash_info_t *info,
41 unsigned long address,
42 volatile unsigned long long data);
43
44/* from flash_asm.S */
45extern void ull_write(unsigned long long volatile *address,
wdenk8bde7f72003-06-27 21:31:46 +000046 unsigned long long volatile *data);
wdenkaffae2b2002-08-17 09:36:01 +000047extern void ull_read(unsigned long long volatile *address,
wdenk8bde7f72003-06-27 21:31:46 +000048 unsigned long long volatile *data);
wdenkaffae2b2002-08-17 09:36:01 +000049
50/*-----------------------------------------------------------------------
51 */
52
53unsigned long flash_init (void)
54{
55 int i;
56 ulong addr;
57
58#ifdef WITH_AUTOSELECT
59 {
60 unsigned long long *f_addr = (unsigned long long *)PHYS_FLASH;
61 unsigned long long f_command, vendor, device;
62 /* Perform Autoselect */
Wolfgang Denk53677ef2008-05-20 16:00:29 +020063 f_command = 0x00AA00AA00AA00AAULL;
wdenkaffae2b2002-08-17 09:36:01 +000064 ull_write(&f_addr[0x555], &f_command);
Wolfgang Denk53677ef2008-05-20 16:00:29 +020065 f_command = 0x0055005500550055ULL;
wdenkaffae2b2002-08-17 09:36:01 +000066 ull_write(&f_addr[0x2AA], &f_command);
Wolfgang Denk53677ef2008-05-20 16:00:29 +020067 f_command = 0x0090009000900090ULL;
wdenkaffae2b2002-08-17 09:36:01 +000068 ull_write(&f_addr[0x555], &f_command);
69 ull_read(&f_addr[0], &vendor);
70 vendor &= 0xffff;
71 ull_read(&f_addr[1], &device);
72 device &= 0xffff;
Wolfgang Denk53677ef2008-05-20 16:00:29 +020073 f_command = 0x00F000F000F000F0ULL;
wdenkaffae2b2002-08-17 09:36:01 +000074 ull_write(&f_addr[0x555], &f_command);
75 if (vendor != VENDOR_AMD || device != AMD_29DL323C_B)
76 return 0;
77 }
78#endif
79
80 /* Init: no FLASHes known */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020081 for (i=0; i<CONFIG_SYS_MAX_FLASH_BANKS; ++i) {
wdenkaffae2b2002-08-17 09:36:01 +000082 flash_info[i].flash_id = FLASH_UNKNOWN;
83 }
84
85 /* 1st bank: 8 x 32 KB sectors */
86 flash_info[0].flash_id = VENDOR_AMD << 16 | AMD_29DL323C_B;
87 flash_info[0].sector_count = 8;
88 flash_info[0].size = flash_info[0].sector_count * 32 * 1024;
89 addr = PHYS_FLASH;
90 for(i = 0; i < flash_info[0].sector_count; i++) {
91 flash_info[0].start[i] = addr;
92 addr += flash_info[0].size / flash_info[0].sector_count;
93 }
94 /* 1st bank: 63 x 256 KB sectors */
95 flash_info[1].flash_id = VENDOR_AMD << 16 | AMD_29DL323C_B;
96 flash_info[1].sector_count = 63;
97 flash_info[1].size = flash_info[1].sector_count * 256 * 1024;
98 for(i = 0; i < flash_info[1].sector_count; i++) {
99 flash_info[1].start[i] = addr;
100 addr += flash_info[1].size / flash_info[1].sector_count;
101 }
102
103 /*
104 * protect monitor and environment sectors
105 */
106
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200107#if CONFIG_SYS_MONITOR_BASE >= PHYS_FLASH
wdenkaffae2b2002-08-17 09:36:01 +0000108 flash_protect(FLAG_PROTECT_SET,
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200109 CONFIG_SYS_MONITOR_BASE,
110 CONFIG_SYS_MONITOR_BASE+monitor_flash_len-1,
wdenkaffae2b2002-08-17 09:36:01 +0000111 &flash_info[0]);
112 flash_protect(FLAG_PROTECT_SET,
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200113 CONFIG_SYS_MONITOR_BASE,
114 CONFIG_SYS_MONITOR_BASE+monitor_flash_len-1,
wdenkaffae2b2002-08-17 09:36:01 +0000115 &flash_info[1]);
116#endif
117
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200118#if defined(CONFIG_ENV_IS_IN_FLASH) && defined(CONFIG_ENV_ADDR)
119# ifndef CONFIG_ENV_SIZE
120# define CONFIG_ENV_SIZE CONFIG_ENV_SECT_SIZE
wdenkaffae2b2002-08-17 09:36:01 +0000121# endif
122 flash_protect(FLAG_PROTECT_SET,
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200123 CONFIG_ENV_ADDR,
124 CONFIG_ENV_ADDR + CONFIG_ENV_SIZE - 1,
wdenkaffae2b2002-08-17 09:36:01 +0000125 &flash_info[0]);
126 flash_protect(FLAG_PROTECT_SET,
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200127 CONFIG_ENV_ADDR,
128 CONFIG_ENV_ADDR + CONFIG_ENV_SIZE - 1,
wdenkaffae2b2002-08-17 09:36:01 +0000129 &flash_info[1]);
130#endif
131
132 return flash_info[0].size + flash_info[1].size;
133}
134
135/*-----------------------------------------------------------------------
136 */
137void flash_print_info (flash_info_t *info)
138{
139 int i;
140
141 if (info->flash_id == FLASH_UNKNOWN) {
142 printf ("missing or unknown FLASH type\n");
143 return;
144 }
145
146 switch (info->flash_id >> 16) {
147 case VENDOR_AMD:
148 printf ("AMD ");
149 break;
150 default:
151 printf ("Unknown Vendor ");
152 break;
153 }
154
155 switch (info->flash_id & FLASH_TYPEMASK) {
156 case AMD_29DL323C_B:
157 printf ("AM29DL323CB (32 Mbit)\n");
158 break;
159 default:
160 printf ("Unknown Chip Type\n");
161 break;
162 }
163
164 printf (" Size: %ld MB in %d Sectors\n",
165 info->size >> 20, info->sector_count);
166
167 printf (" Sector Start Addresses:");
168 for (i=0; i<info->sector_count; ++i) {
169 if ((i % 5) == 0)
170 printf ("\n ");
171 printf (" %08lX%s",
172 info->start[i],
173 info->protect[i] ? " (RO)" : " "
174 );
175 }
176 printf ("\n");
177 return;
178}
179
180/*-----------------------------------------------------------------------
181 */
182
183int flash_erase (flash_info_t *info, int s_first, int s_last)
184{
185 int flag, prot, sect, l_sect;
186 ulong start;
187 unsigned long long volatile *f_addr;
188 unsigned long long volatile f_command;
189
190 if ((s_first < 0) || (s_first > s_last)) {
191 if (info->flash_id == FLASH_UNKNOWN) {
192 printf ("- missing\n");
193 } else {
194 printf ("- no sectors to erase\n");
195 }
196 return 1;
197 }
198
199 prot = 0;
200 for (sect = s_first; sect <= s_last; sect++) {
201 if (info->protect[sect]) {
202 prot++;
203 }
204 }
205 if (prot) {
206 printf ("- Warning: %d protected sectors will not be erased!\n",
207 prot);
208 } else {
209 printf ("\n");
210 }
211
Wolfgang Denk53677ef2008-05-20 16:00:29 +0200212 f_addr = (unsigned long long *)info->start[0];
213 f_command = 0x00AA00AA00AA00AAULL;
wdenkaffae2b2002-08-17 09:36:01 +0000214 ull_write(&f_addr[0x555], &f_command);
Wolfgang Denk53677ef2008-05-20 16:00:29 +0200215 f_command = 0x0055005500550055ULL;
wdenkaffae2b2002-08-17 09:36:01 +0000216 ull_write(&f_addr[0x2AA], &f_command);
Wolfgang Denk53677ef2008-05-20 16:00:29 +0200217 f_command = 0x0080008000800080ULL;
wdenkaffae2b2002-08-17 09:36:01 +0000218 ull_write(&f_addr[0x555], &f_command);
Wolfgang Denk53677ef2008-05-20 16:00:29 +0200219 f_command = 0x00AA00AA00AA00AAULL;
wdenkaffae2b2002-08-17 09:36:01 +0000220 ull_write(&f_addr[0x555], &f_command);
Wolfgang Denk53677ef2008-05-20 16:00:29 +0200221 f_command = 0x0055005500550055ULL;
wdenkaffae2b2002-08-17 09:36:01 +0000222 ull_write(&f_addr[0x2AA], &f_command);
223
224 /* Disable interrupts which might cause a timeout here */
225 flag = disable_interrupts();
226
227 /* Start erase on unprotected sectors */
228 for (l_sect = -1, sect = s_first; sect<=s_last; sect++) {
229 if (info->protect[sect] == 0) { /* not protected */
230
Wolfgang Denk53677ef2008-05-20 16:00:29 +0200231 f_addr =
wdenkaffae2b2002-08-17 09:36:01 +0000232 (unsigned long long *)(info->start[sect]);
Wolfgang Denk53677ef2008-05-20 16:00:29 +0200233 f_command = 0x0030003000300030ULL;
wdenkaffae2b2002-08-17 09:36:01 +0000234 ull_write(f_addr, &f_command);
235 l_sect = sect;
236 }
237 }
238
239 /* re-enable interrupts if necessary */
240 if (flag)
241 enable_interrupts();
242
243 start = get_timer (0);
244 do
245 {
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200246 if (get_timer(start) > CONFIG_SYS_FLASH_ERASE_TOUT)
wdenkaffae2b2002-08-17 09:36:01 +0000247 { /* write reset command, command address is unimportant */
248 /* this command turns the flash back to read mode */
249 f_addr =
250 (unsigned long long *)(info->start[l_sect]);
Wolfgang Denk53677ef2008-05-20 16:00:29 +0200251 f_command = 0x00F000F000F000F0ULL;
wdenkaffae2b2002-08-17 09:36:01 +0000252 ull_write(f_addr, &f_command);
253 printf (" timeout\n");
254 return 1;
wdenk8bde7f72003-06-27 21:31:46 +0000255 }
wdenkaffae2b2002-08-17 09:36:01 +0000256 } while(*f_addr != 0xFFFFFFFFFFFFFFFFULL);
257
258 printf (" done\n");
259 return 0;
260}
261
262/*-----------------------------------------------------------------------
263 * Copy memory to flash, returns:
264 * 0 - OK
265 * 1 - write timeout
266 * 2 - Flash not erased
267 */
268
269int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
270{
271 unsigned long cp, wp;
272 unsigned long long data;
273 int i, l, rc;
274
275 wp = (addr & ~7); /* get lower long long aligned address */
276
277 /*
278 * handle unaligned start bytes
279 */
280 if ((l = addr - wp) != 0) {
281 data = 0;
282 for (i=0, cp=wp; i<l; ++i, ++cp) {
283 data = (data << 8) | (*(uchar *)cp);
284 }
285 for (; i<8 && cnt>0; ++i) {
286 data = (data << 8) | *src++;
287 --cnt;
288 ++cp;
289 }
290 for (; cnt==0 && i<8; ++i, ++cp) {
291 data = (data << 8) | (*(uchar *)cp);
292 }
293
294 if ((rc = write_ull(info, wp, data)) != 0) {
295 return rc;
296 }
297 wp += 4;
298 }
299
300 /*
301 * handle long long aligned part
302 */
303 while (cnt >= 8) {
304 data = 0;
305 for (i=0; i<8; ++i) {
306 data = (data << 8) | *src++;
307 }
308 if ((rc = write_ull(info, wp, data)) != 0) {
309 return rc;
310 }
311 wp += 8;
312 cnt -= 8;
313 }
314
315 if (cnt == 0) {
316 return ERR_OK;
317 }
318
319 /*
320 * handle unaligned tail bytes
321 */
322 data = 0;
323 for (i=0, cp=wp; i<8 && cnt>0; ++i, ++cp) {
324 data = (data << 8) | *src++;
325 --cnt;
326 }
327 for (; i<8; ++i, ++cp) {
328 data = (data << 8) | (*(uchar *)cp);
329 }
330
331 return write_ull(info, wp, data);
332}
333
334/*---------------------------------------------------------------------------
335*
336* FUNCTION NAME: write_ull
337*
338* DESCRIPTION: writes 8 bytes to flash
339*
340* EXTERNAL EFFECT: nothing
341*
342* PARAMETERS: 32 bit long pointer to address, 64 bit long pointer to data
343*
Wolfgang Denk53677ef2008-05-20 16:00:29 +0200344* RETURNS: 0 if OK, 1 if timeout, 4 if parameter error
wdenkaffae2b2002-08-17 09:36:01 +0000345*--------------------------------------------------------------------------*/
346
347static unsigned char write_ull(flash_info_t *info,
348 unsigned long address,
349 volatile unsigned long long data)
350{
351 static unsigned long long f_command;
352 static unsigned long long *f_addr;
353 ulong start;
354
355 /* address muss be 8-aligned! */
356 if (address & 0x7)
357 return ERR_ALIGN;
358
Wolfgang Denk53677ef2008-05-20 16:00:29 +0200359 f_addr = (unsigned long long *)info->start[0];
360 f_command = 0x00AA00AA00AA00AAULL;
wdenkaffae2b2002-08-17 09:36:01 +0000361 ull_write(&f_addr[0x555], &f_command);
Wolfgang Denk53677ef2008-05-20 16:00:29 +0200362 f_command = 0x0055005500550055ULL;
wdenkaffae2b2002-08-17 09:36:01 +0000363 ull_write(&f_addr[0x2AA], &f_command);
Wolfgang Denk53677ef2008-05-20 16:00:29 +0200364 f_command = 0x00A000A000A000A0ULL;
wdenkaffae2b2002-08-17 09:36:01 +0000365 ull_write(&f_addr[0x555], &f_command);
366
Wolfgang Denk53677ef2008-05-20 16:00:29 +0200367 f_addr = (unsigned long long *)address;
368 f_command = data;
wdenkaffae2b2002-08-17 09:36:01 +0000369 ull_write(f_addr, &f_command);
370
371 start = get_timer (0);
372 do
373 {
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200374 if (get_timer(start) > CONFIG_SYS_FLASH_WRITE_TOUT)
wdenkaffae2b2002-08-17 09:36:01 +0000375 {
376 /* write reset command, command address is unimportant */
377 /* this command turns the flash back to read mode */
Wolfgang Denk53677ef2008-05-20 16:00:29 +0200378 f_addr = (unsigned long long *)info->start[0];
379 f_command = 0x00F000F000F000F0ULL;
wdenkaffae2b2002-08-17 09:36:01 +0000380 ull_write(f_addr, &f_command);
381 return ERR_TIMOUT;
382 }
383 } while(*((unsigned long long *)address) != data);
384
385 return 0;
386}