3 * Marius Groeger <mgroeger@sysgo.de>
4 * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
7 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
9 * Flash Routines for AM290[48]0B devices
11 *--------------------------------------------------------------------
12 * SPDX-License-Identifier: GPL-2.0+
18 /* flash hardware ids */
19 #define VENDOR_AMD 0x0001
20 #define AMD_29DL323C_B 0x2253
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.
26 #undef WITH_AUTOSELECT
28 flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS]; /* info for FLASH chips */
36 /*-----------------------------------------------------------------------
40 static unsigned char write_ull(flash_info_t *info,
41 unsigned long address,
42 volatile unsigned long long data);
44 /* from flash_asm.S */
45 extern void ull_write(unsigned long long volatile *address,
46 unsigned long long volatile *data);
47 extern void ull_read(unsigned long long volatile *address,
48 unsigned long long volatile *data);
50 /*-----------------------------------------------------------------------
53 unsigned long flash_init (void)
58 #ifdef WITH_AUTOSELECT
60 unsigned long long *f_addr = (unsigned long long *)PHYS_FLASH;
61 unsigned long long f_command, vendor, device;
62 /* Perform Autoselect */
63 f_command = 0x00AA00AA00AA00AAULL;
64 ull_write(&f_addr[0x555], &f_command);
65 f_command = 0x0055005500550055ULL;
66 ull_write(&f_addr[0x2AA], &f_command);
67 f_command = 0x0090009000900090ULL;
68 ull_write(&f_addr[0x555], &f_command);
69 ull_read(&f_addr[0], &vendor);
71 ull_read(&f_addr[1], &device);
73 f_command = 0x00F000F000F000F0ULL;
74 ull_write(&f_addr[0x555], &f_command);
75 if (vendor != VENDOR_AMD || device != AMD_29DL323C_B)
80 /* Init: no FLASHes known */
81 for (i=0; i<CONFIG_SYS_MAX_FLASH_BANKS; ++i) {
82 flash_info[i].flash_id = FLASH_UNKNOWN;
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;
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;
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;
104 * protect monitor and environment sectors
107 #if CONFIG_SYS_MONITOR_BASE >= PHYS_FLASH
108 flash_protect(FLAG_PROTECT_SET,
109 CONFIG_SYS_MONITOR_BASE,
110 CONFIG_SYS_MONITOR_BASE+monitor_flash_len-1,
112 flash_protect(FLAG_PROTECT_SET,
113 CONFIG_SYS_MONITOR_BASE,
114 CONFIG_SYS_MONITOR_BASE+monitor_flash_len-1,
118 #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
122 flash_protect(FLAG_PROTECT_SET,
124 CONFIG_ENV_ADDR + CONFIG_ENV_SIZE - 1,
126 flash_protect(FLAG_PROTECT_SET,
128 CONFIG_ENV_ADDR + CONFIG_ENV_SIZE - 1,
132 return flash_info[0].size + flash_info[1].size;
135 /*-----------------------------------------------------------------------
137 void flash_print_info (flash_info_t *info)
141 if (info->flash_id == FLASH_UNKNOWN) {
142 printf ("missing or unknown FLASH type\n");
146 switch (info->flash_id >> 16) {
151 printf ("Unknown Vendor ");
155 switch (info->flash_id & FLASH_TYPEMASK) {
157 printf ("AM29DL323CB (32 Mbit)\n");
160 printf ("Unknown Chip Type\n");
164 printf (" Size: %ld MB in %d Sectors\n",
165 info->size >> 20, info->sector_count);
167 printf (" Sector Start Addresses:");
168 for (i=0; i<info->sector_count; ++i) {
173 info->protect[i] ? " (RO)" : " "
180 /*-----------------------------------------------------------------------
183 int flash_erase (flash_info_t *info, int s_first, int s_last)
185 int flag, prot, sect, l_sect;
187 unsigned long long volatile *f_addr;
188 unsigned long long volatile f_command;
190 if ((s_first < 0) || (s_first > s_last)) {
191 if (info->flash_id == FLASH_UNKNOWN) {
192 printf ("- missing\n");
194 printf ("- no sectors to erase\n");
200 for (sect = s_first; sect <= s_last; sect++) {
201 if (info->protect[sect]) {
206 printf ("- Warning: %d protected sectors will not be erased!\n",
212 f_addr = (unsigned long long *)info->start[0];
213 f_command = 0x00AA00AA00AA00AAULL;
214 ull_write(&f_addr[0x555], &f_command);
215 f_command = 0x0055005500550055ULL;
216 ull_write(&f_addr[0x2AA], &f_command);
217 f_command = 0x0080008000800080ULL;
218 ull_write(&f_addr[0x555], &f_command);
219 f_command = 0x00AA00AA00AA00AAULL;
220 ull_write(&f_addr[0x555], &f_command);
221 f_command = 0x0055005500550055ULL;
222 ull_write(&f_addr[0x2AA], &f_command);
224 /* Disable interrupts which might cause a timeout here */
225 flag = disable_interrupts();
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 */
232 (unsigned long long *)(info->start[sect]);
233 f_command = 0x0030003000300030ULL;
234 ull_write(f_addr, &f_command);
239 /* re-enable interrupts if necessary */
243 start = get_timer (0);
246 if (get_timer(start) > CONFIG_SYS_FLASH_ERASE_TOUT)
247 { /* write reset command, command address is unimportant */
248 /* this command turns the flash back to read mode */
250 (unsigned long long *)(info->start[l_sect]);
251 f_command = 0x00F000F000F000F0ULL;
252 ull_write(f_addr, &f_command);
253 printf (" timeout\n");
256 } while(*f_addr != 0xFFFFFFFFFFFFFFFFULL);
262 /*-----------------------------------------------------------------------
263 * Copy memory to flash, returns:
266 * 2 - Flash not erased
269 int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
271 unsigned long cp, wp;
272 unsigned long long data;
275 wp = (addr & ~7); /* get lower long long aligned address */
278 * handle unaligned start bytes
280 if ((l = addr - wp) != 0) {
282 for (i=0, cp=wp; i<l; ++i, ++cp) {
283 data = (data << 8) | (*(uchar *)cp);
285 for (; i<8 && cnt>0; ++i) {
286 data = (data << 8) | *src++;
290 for (; cnt==0 && i<8; ++i, ++cp) {
291 data = (data << 8) | (*(uchar *)cp);
294 if ((rc = write_ull(info, wp, data)) != 0) {
301 * handle long long aligned part
305 for (i=0; i<8; ++i) {
306 data = (data << 8) | *src++;
308 if ((rc = write_ull(info, wp, data)) != 0) {
320 * handle unaligned tail bytes
323 for (i=0, cp=wp; i<8 && cnt>0; ++i, ++cp) {
324 data = (data << 8) | *src++;
327 for (; i<8; ++i, ++cp) {
328 data = (data << 8) | (*(uchar *)cp);
331 return write_ull(info, wp, data);
334 /*---------------------------------------------------------------------------
336 * FUNCTION NAME: write_ull
338 * DESCRIPTION: writes 8 bytes to flash
340 * EXTERNAL EFFECT: nothing
342 * PARAMETERS: 32 bit long pointer to address, 64 bit long pointer to data
344 * RETURNS: 0 if OK, 1 if timeout, 4 if parameter error
345 *--------------------------------------------------------------------------*/
347 static unsigned char write_ull(flash_info_t *info,
348 unsigned long address,
349 volatile unsigned long long data)
351 static unsigned long long f_command;
352 static unsigned long long *f_addr;
355 /* address muss be 8-aligned! */
359 f_addr = (unsigned long long *)info->start[0];
360 f_command = 0x00AA00AA00AA00AAULL;
361 ull_write(&f_addr[0x555], &f_command);
362 f_command = 0x0055005500550055ULL;
363 ull_write(&f_addr[0x2AA], &f_command);
364 f_command = 0x00A000A000A000A0ULL;
365 ull_write(&f_addr[0x555], &f_command);
367 f_addr = (unsigned long long *)address;
369 ull_write(f_addr, &f_command);
371 start = get_timer (0);
374 if (get_timer(start) > CONFIG_SYS_FLASH_WRITE_TOUT)
376 /* write reset command, command address is unimportant */
377 /* this command turns the flash back to read mode */
378 f_addr = (unsigned long long *)info->start[0];
379 f_command = 0x00F000F000F000F0ULL;
380 ull_write(f_addr, &f_command);
383 } while(*((unsigned long long *)address) != data);