3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
5 * SPDX-License-Identifier: GPL-2.0+
10 #include <linux/byteorder/swab.h>
12 flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS]; /* info for FLASH chips */
14 /*-----------------------------------------------------------------------
17 #define FLAG_PROTECT_SET 0x01
18 #define FLAG_PROTECT_CLEAR 0x02
20 /* Board support for 1 or 2 flash devices */
21 #undef FLASH_PORT_WIDTH32
22 #define FLASH_PORT_WIDTH16
24 #ifdef FLASH_PORT_WIDTH16
25 #define FLASH_PORT_WIDTH ushort
26 #define FLASH_PORT_WIDTHV vu_short
27 #define SWAP(x) __swab16(x)
29 #define FLASH_PORT_WIDTH ulong
30 #define FLASH_PORT_WIDTHV vu_long
31 #define SWAP(x) __swab32(x)
34 #define FPW FLASH_PORT_WIDTH
35 #define FPWV FLASH_PORT_WIDTHV
37 /*-----------------------------------------------------------------------
40 static ulong flash_get_size (FPW *addr, flash_info_t *info);
41 static int write_data (flash_info_t *info, ulong dest, FPW data);
42 static void flash_get_offsets (ulong base, flash_info_t *info);
44 /*-----------------------------------------------------------------------
47 unsigned long flash_init (void)
49 volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR;
50 volatile memctl8xx_t *memctl = &immap->im_memctl;
51 unsigned long size_b0;
54 /* Init: no FLASHes known */
55 for (i=0; i<CONFIG_SYS_MAX_FLASH_BANKS; ++i) {
56 flash_info[i].flash_id = FLASH_UNKNOWN;
59 /* Static FLASH Bank configuration here - FIXME XXX */
60 size_b0 = flash_get_size((FPW *)FLASH_BASE0_PRELIM, &flash_info[0]);
62 if (flash_info[0].flash_id == FLASH_UNKNOWN) {
63 printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
64 size_b0, size_b0<<20);
67 /* Remap FLASH according to real size */
68 memctl->memc_or0 = CONFIG_SYS_OR_TIMING_FLASH | (-size_b0 & 0xFFFF8000);
69 memctl->memc_br0 = (CONFIG_SYS_FLASH_BASE & BR_BA_MSK) | BR_PS_16 | BR_MS_GPCM | BR_V;
71 /* Re-do sizing to get full correct info */
72 size_b0 = flash_get_size((FPW *)CONFIG_SYS_FLASH_BASE, &flash_info[0]);
74 flash_get_offsets (CONFIG_SYS_FLASH_BASE, &flash_info[0]);
76 /* monitor protection ON by default */
77 (void)flash_protect(FLAG_PROTECT_SET,
78 CONFIG_SYS_FLASH_BASE,
79 CONFIG_SYS_FLASH_BASE+monitor_flash_len-1,
82 flash_info[0].size = size_b0;
87 /*-----------------------------------------------------------------------
89 static void flash_get_offsets (ulong base, flash_info_t *info)
93 if (info->flash_id == FLASH_UNKNOWN) {
97 if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL) {
98 for (i = 0; i < info->sector_count; i++) {
99 info->start[i] = base + (i * 0x00020000);
104 /*-----------------------------------------------------------------------
106 void flash_print_info (flash_info_t *info)
110 if (info->flash_id == FLASH_UNKNOWN) {
111 printf ("missing or unknown FLASH type\n");
115 switch (info->flash_id & FLASH_VENDMASK) {
116 case FLASH_MAN_INTEL: printf ("INTEL "); break;
117 default: printf ("Unknown Vendor "); break;
120 switch (info->flash_id & FLASH_TYPEMASK) {
121 case FLASH_28F640J5 :
122 printf ("28F640J5 \n"); break;
123 default: printf ("Unknown Chip Type=0x%lXh\n",
124 info->flash_id & FLASH_TYPEMASK); break;
127 printf (" Size: %ld MB in %d Sectors\n",
128 info->size >> 20, info->sector_count);
130 printf (" Sector Start Addresses:");
131 for (i=0; i<info->sector_count; ++i) {
136 info->protect[i] ? " (RO)" : " "
142 /*-----------------------------------------------------------------------
146 /*-----------------------------------------------------------------------
150 * The following code cannot be run from FLASH!
153 static ulong flash_get_size (FPW *addr, flash_info_t *info)
157 /* Write auto select command: read Manufacturer ID */
158 addr[0x5555] = (FPW)0xAA00AA00;
159 addr[0x2AAA] = (FPW)0x55005500;
160 addr[0x5555] = (FPW)0x90009000;
162 value = SWAP(addr[0]);
165 case (FPW)INTEL_MANUFACT:
166 info->flash_id = FLASH_MAN_INTEL;
169 info->flash_id = FLASH_UNKNOWN;
170 info->sector_count = 0;
172 addr[0] = (FPW)0xFF00FF00; /* restore read mode */
173 return (0); /* no or unknown flash */
176 value = SWAP(addr[1]); /* device ID no swap !*/
179 case (FPW)INTEL_ID_28F640J5 :
180 info->flash_id += FLASH_28F640J5 ;
181 info->sector_count = 64;
182 info->size = 0x00800000;
186 info->flash_id = FLASH_UNKNOWN;
190 if (info->sector_count > CONFIG_SYS_MAX_FLASH_SECT) {
191 printf ("** ERROR: sector count %d > max (%d) **\n",
192 info->sector_count, CONFIG_SYS_MAX_FLASH_SECT);
193 info->sector_count = CONFIG_SYS_MAX_FLASH_SECT;
196 addr[0] = (FPW)0xFF00FF00; /* restore read mode */
202 /*-----------------------------------------------------------------------
205 int flash_erase (flash_info_t *info, int s_first, int s_last)
207 int flag, prot, sect;
208 ulong type, start, now, last;
211 if ((s_first < 0) || (s_first > s_last)) {
212 if (info->flash_id == FLASH_UNKNOWN) {
213 printf ("- missing\n");
215 printf ("- no sectors to erase\n");
220 type = (info->flash_id & FLASH_VENDMASK);
221 if ((type != FLASH_MAN_INTEL)) {
222 printf ("Can't erase unknown flash type %08lx - aborted\n",
228 for (sect=s_first; sect<=s_last; ++sect) {
229 if (info->protect[sect]) {
235 printf ("- Warning: %d protected sectors will not be erased!\n",
241 start = get_timer (0);
243 /* Start erase on unprotected sectors */
244 for (sect = s_first; sect<=s_last; sect++) {
245 if (info->protect[sect] == 0) { /* not protected */
246 FPWV *addr = (FPWV *)(info->start[sect]);
249 /* Disable interrupts which might cause a timeout here */
250 flag = disable_interrupts();
252 *addr = (FPW)0x50005000; /* clear status register */
253 *addr = (FPW)0x20002000; /* erase setup */
254 *addr = (FPW)0xD000D000; /* erase confirm */
256 /* re-enable interrupts if necessary */
260 /* wait at least 80us - let's wait 1 ms */
263 while (((status = SWAP(*addr)) & (FPW)0x00800080) != (FPW)0x00800080) {
264 if ((now=get_timer(start)) > CONFIG_SYS_FLASH_ERASE_TOUT) {
265 printf ("Timeout\n");
266 *addr = (FPW)0xB000B000; /* suspend erase */
267 *addr = (FPW)0xFF00FF00; /* reset to read mode */
272 /* show that we're waiting */
273 if ((now - last) > 1000) { /* every second */
279 *addr = (FPW)0xFF00FF00; /* reset to read mode */
286 /*-----------------------------------------------------------------------
287 * Copy memory to flash, returns:
290 * 2 - Flash not erased
291 * 4 - Flash not identified
294 int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
298 int i, l, rc, port_width;
300 if (info->flash_id == FLASH_UNKNOWN) {
303 /* get lower word aligned address */
304 #ifdef FLASH_PORT_WIDTH16
313 * handle unaligned start bytes
315 if ((l = addr - wp) != 0) {
317 for (i=0, cp=wp; i<l; ++i, ++cp)
318 data = (data << 8) | (*(uchar *)cp);
320 for (; i<port_width && cnt>0; ++i) {
321 data = (data << 8) | *src++;
325 for (; cnt==0 && i<port_width; ++i, ++cp) {
326 data = (data << 8) | (*(uchar *)cp);
329 if ((rc = write_data(info, wp, data)) != 0) {
336 * handle word aligned part
338 while (cnt >= port_width) {
340 for (i=0; i<port_width; ++i) {
341 data = (data << 8) | *src++;
343 if ((rc = write_data(info, wp, data)) != 0) {
348 if ((wp & 0xfff) == 0)
360 * handle unaligned tail bytes
363 for (i=0, cp=wp; i<port_width && cnt>0; ++i, ++cp) {
364 data = (data << 8) | *src++;
367 for (; i<port_width; ++i, ++cp) {
368 data = (data << 8) | (*(uchar *)cp);
371 return (write_data(info, wp, data));
374 /*-----------------------------------------------------------------------
375 * Write a word or halfword to Flash, returns:
378 * 2 - Flash not erased
380 static int write_data (flash_info_t *info, ulong dest, FPW data)
382 FPWV *addr = (FPWV *)dest;
387 /* Check if Flash is (sufficiently) erased */
388 if ((*addr & data) != data) {
389 printf("not erased at %08lx (%x)\n",(ulong)addr,*addr);
392 /* Disable interrupts which might cause a timeout here */
393 flag = disable_interrupts();
395 *addr = (FPW)0x40004000; /* write setup */
398 /* re-enable interrupts if necessary */
402 start = get_timer (0);
404 while (((status = SWAP(*addr)) & (FPW)0x00800080) != (FPW)0x00800080) {
405 if (get_timer(start) > CONFIG_SYS_FLASH_WRITE_TOUT) {
406 *addr = (FPW)0xFF00FF00; /* restore read mode */
411 *addr = (FPW)0xFF00FF00; /* restore read mode */