xref: /rk3399_rockchip-uboot/board/freescale/m5253demo/flash.c (revision b411f2af49117171a6f5d696f08a01b2f4a35c3b)
16d33c6acSTsiChung Liew /*
26d33c6acSTsiChung Liew  * (C) Copyright 2000-2003
36d33c6acSTsiChung Liew  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
46d33c6acSTsiChung Liew  *
56d33c6acSTsiChung Liew  * Copyright (C) 2004-2007 Freescale Semiconductor, Inc.
66d33c6acSTsiChung Liew  * TsiChung Liew (Tsi-Chung.Liew@freescale.com)
76d33c6acSTsiChung Liew  *
81a459660SWolfgang Denk  * SPDX-License-Identifier:	GPL-2.0+
96d33c6acSTsiChung Liew  */
106d33c6acSTsiChung Liew 
116d33c6acSTsiChung Liew #include <common.h>
126d33c6acSTsiChung Liew 
136d33c6acSTsiChung Liew #include <asm/immap.h>
146d33c6acSTsiChung Liew 
156d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifndef CONFIG_SYS_FLASH_CFI
166d33c6acSTsiChung Liew typedef unsigned short FLASH_PORT_WIDTH;
176d33c6acSTsiChung Liew typedef volatile unsigned short FLASH_PORT_WIDTHV;
186d33c6acSTsiChung Liew 
196d33c6acSTsiChung Liew #define FPW             FLASH_PORT_WIDTH
206d33c6acSTsiChung Liew #define FPWV            FLASH_PORT_WIDTHV
216d33c6acSTsiChung Liew 
226d33c6acSTsiChung Liew #define FLASH_CYCLE1    0x5555
236d33c6acSTsiChung Liew #define FLASH_CYCLE2    0x2aaa
246d33c6acSTsiChung Liew 
256d33c6acSTsiChung Liew #define SYNC			__asm__("nop")
266d33c6acSTsiChung Liew 
276d33c6acSTsiChung Liew /*-----------------------------------------------------------------------
286d33c6acSTsiChung Liew  * Functions
296d33c6acSTsiChung Liew  */
306d33c6acSTsiChung Liew 
316d33c6acSTsiChung Liew ulong flash_get_size(FPWV * addr, flash_info_t * info);
326d33c6acSTsiChung Liew int flash_get_offsets(ulong base, flash_info_t * info);
336d33c6acSTsiChung Liew int write_word(flash_info_t * info, FPWV * dest, u16 data);
34*b411f2afSTom Rini static inline void spin_wheel(void);
356d33c6acSTsiChung Liew 
366d0f6bcfSJean-Christophe PLAGNIOL-VILLARD flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS];
376d33c6acSTsiChung Liew 
flash_init(void)386d33c6acSTsiChung Liew ulong flash_init(void)
396d33c6acSTsiChung Liew {
406d33c6acSTsiChung Liew 	ulong size = 0;
416d33c6acSTsiChung Liew 	ulong fbase = 0;
426d33c6acSTsiChung Liew 
436d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 	fbase = (ulong) CONFIG_SYS_FLASH_BASE;
446d33c6acSTsiChung Liew 	flash_get_size((FPWV *) fbase, &flash_info[0]);
456d33c6acSTsiChung Liew 	flash_get_offsets((ulong) fbase, &flash_info[0]);
466d33c6acSTsiChung Liew 	fbase += flash_info[0].size;
476d33c6acSTsiChung Liew 	size += flash_info[0].size;
486d33c6acSTsiChung Liew 
496d33c6acSTsiChung Liew 	/* Protect monitor and environment sectors */
506d33c6acSTsiChung Liew 	flash_protect(FLAG_PROTECT_SET,
516d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 		      CONFIG_SYS_MONITOR_BASE,
526d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 		      CONFIG_SYS_MONITOR_BASE + monitor_flash_len - 1, &flash_info[0]);
536d33c6acSTsiChung Liew 
546d33c6acSTsiChung Liew 	return size;
556d33c6acSTsiChung Liew }
566d33c6acSTsiChung Liew 
flash_get_offsets(ulong base,flash_info_t * info)576d33c6acSTsiChung Liew int flash_get_offsets(ulong base, flash_info_t * info)
586d33c6acSTsiChung Liew {
5961f06b14SMasahiro Yamada 	int i;
606d33c6acSTsiChung Liew 
616d33c6acSTsiChung Liew 	if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_SST) {
626d33c6acSTsiChung Liew 
636d33c6acSTsiChung Liew 		info->start[0] = base;
6461f06b14SMasahiro Yamada 		info->protect[0] = 0;
6561f06b14SMasahiro Yamada 		for (i = 1; i < CONFIG_SYS_SST_SECT; i++) {
6661f06b14SMasahiro Yamada 			info->start[i] = info->start[i - 1]
6761f06b14SMasahiro Yamada 						+ CONFIG_SYS_SST_SECTSZ;
6861f06b14SMasahiro Yamada 			info->protect[i] = 0;
696d33c6acSTsiChung Liew 		}
706d33c6acSTsiChung Liew 	}
716d33c6acSTsiChung Liew 
726d33c6acSTsiChung Liew 	return ERR_OK;
736d33c6acSTsiChung Liew }
746d33c6acSTsiChung Liew 
flash_print_info(flash_info_t * info)756d33c6acSTsiChung Liew void flash_print_info(flash_info_t * info)
766d33c6acSTsiChung Liew {
776d33c6acSTsiChung Liew 	int i;
786d33c6acSTsiChung Liew 
796d33c6acSTsiChung Liew 	switch (info->flash_id & FLASH_VENDMASK) {
806d33c6acSTsiChung Liew 	case FLASH_MAN_SST:
816d33c6acSTsiChung Liew 		printf("SST ");
826d33c6acSTsiChung Liew 		break;
836d33c6acSTsiChung Liew 	default:
846d33c6acSTsiChung Liew 		printf("Unknown Vendor ");
856d33c6acSTsiChung Liew 		break;
866d33c6acSTsiChung Liew 	}
876d33c6acSTsiChung Liew 
886d33c6acSTsiChung Liew 	switch (info->flash_id & FLASH_TYPEMASK) {
896d33c6acSTsiChung Liew 	case FLASH_SST6401B:
906d33c6acSTsiChung Liew 		printf("SST39VF6401B\n");
916d33c6acSTsiChung Liew 		break;
926d33c6acSTsiChung Liew 	default:
936d33c6acSTsiChung Liew 		printf("Unknown Chip Type\n");
946d33c6acSTsiChung Liew 		return;
956d33c6acSTsiChung Liew 	}
966d33c6acSTsiChung Liew 
976d33c6acSTsiChung Liew 	if (info->size > 0x100000) {
986d33c6acSTsiChung Liew 		int remainder;
996d33c6acSTsiChung Liew 
1006d33c6acSTsiChung Liew 		printf("  Size: %ld", info->size >> 20);
1016d33c6acSTsiChung Liew 
1026d33c6acSTsiChung Liew 		remainder = (info->size % 0x100000);
1036d33c6acSTsiChung Liew 		if (remainder) {
1046d33c6acSTsiChung Liew 			remainder >>= 10;
1056d33c6acSTsiChung Liew 			remainder = (int)((float)
1066d33c6acSTsiChung Liew 					  (((float)remainder / (float)1024) *
1076d33c6acSTsiChung Liew 					   10000));
1086d33c6acSTsiChung Liew 			printf(".%d ", remainder);
1096d33c6acSTsiChung Liew 		}
1106d33c6acSTsiChung Liew 
1116d33c6acSTsiChung Liew 		printf("MB in %d Sectors\n", info->sector_count);
1126d33c6acSTsiChung Liew 	} else
1136d33c6acSTsiChung Liew 		printf("  Size: %ld KB in %d Sectors\n",
1146d33c6acSTsiChung Liew 		       info->size >> 10, info->sector_count);
1156d33c6acSTsiChung Liew 
1166d33c6acSTsiChung Liew 	printf("  Sector Start Addresses:");
1176d33c6acSTsiChung Liew 	for (i = 0; i < info->sector_count; ++i) {
1186d33c6acSTsiChung Liew 		if ((i % 5) == 0)
1196d33c6acSTsiChung Liew 			printf("\n   ");
1206d33c6acSTsiChung Liew 		printf(" %08lX%s",
1216d33c6acSTsiChung Liew 		       info->start[i], info->protect[i] ? " (RO)" : "     ");
1226d33c6acSTsiChung Liew 	}
1236d33c6acSTsiChung Liew 	printf("\n");
1246d33c6acSTsiChung Liew }
1256d33c6acSTsiChung Liew 
1266d33c6acSTsiChung Liew /*
1276d33c6acSTsiChung Liew  * The following code cannot be run from FLASH!
1286d33c6acSTsiChung Liew  */
flash_get_size(FPWV * addr,flash_info_t * info)1296d33c6acSTsiChung Liew ulong flash_get_size(FPWV * addr, flash_info_t * info)
1306d33c6acSTsiChung Liew {
1316d33c6acSTsiChung Liew 	u16 value;
1326d33c6acSTsiChung Liew 
1336d33c6acSTsiChung Liew 	addr[FLASH_CYCLE1] = (FPWV) 0x00AA00AA;	/* for Atmel, Intel ignores this */
1346d33c6acSTsiChung Liew 	addr[FLASH_CYCLE2] = (FPWV) 0x00550055;	/* for Atmel, Intel ignores this */
1356d33c6acSTsiChung Liew 	addr[FLASH_CYCLE1] = (FPWV) 0x00900090;	/* selects Intel or Atmel */
1366d33c6acSTsiChung Liew 
1376d33c6acSTsiChung Liew 	switch (addr[0] & 0xffff) {
1386d33c6acSTsiChung Liew 	case (u8) SST_MANUFACT:
1396d33c6acSTsiChung Liew 		info->flash_id = FLASH_MAN_SST;
1406d33c6acSTsiChung Liew 		value = addr[1];
1416d33c6acSTsiChung Liew 		break;
1426d33c6acSTsiChung Liew 	default:
1436d33c6acSTsiChung Liew 		printf("Unknown Flash\n");
1446d33c6acSTsiChung Liew 		info->flash_id = FLASH_UNKNOWN;
1456d33c6acSTsiChung Liew 		info->sector_count = 0;
1466d33c6acSTsiChung Liew 		info->size = 0;
1476d33c6acSTsiChung Liew 
1486d33c6acSTsiChung Liew 		*addr = (FPW) 0x00F000F0;
1496d33c6acSTsiChung Liew 		return (0);	/* no or unknown flash  */
1506d33c6acSTsiChung Liew 	}
1516d33c6acSTsiChung Liew 
1526d33c6acSTsiChung Liew 	switch (value) {
1536d33c6acSTsiChung Liew 	case (u16) SST_ID_xF6401B:
1546d33c6acSTsiChung Liew 		info->flash_id += FLASH_SST6401B;
1556d33c6acSTsiChung Liew 		break;
1566d33c6acSTsiChung Liew 	default:
1576d33c6acSTsiChung Liew 		info->flash_id = FLASH_UNKNOWN;
1586d33c6acSTsiChung Liew 		break;
1596d33c6acSTsiChung Liew 	}
1606d33c6acSTsiChung Liew 
1616d33c6acSTsiChung Liew 	info->sector_count = 0;
1626d33c6acSTsiChung Liew 	info->size = 0;
1636d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 	info->sector_count = CONFIG_SYS_SST_SECT;
1646d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 	info->size = CONFIG_SYS_SST_SECT * CONFIG_SYS_SST_SECTSZ;
1656d33c6acSTsiChung Liew 
1666d33c6acSTsiChung Liew 	/* reset ID mode */
1676d33c6acSTsiChung Liew 	*addr = (FPWV) 0x00F000F0;
1686d33c6acSTsiChung Liew 
1696d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 	if (info->sector_count > CONFIG_SYS_MAX_FLASH_SECT) {
1706d33c6acSTsiChung Liew 		printf("** ERROR: sector count %d > max (%d) **\n",
1716d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 		       info->sector_count, CONFIG_SYS_MAX_FLASH_SECT);
1726d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 		info->sector_count = CONFIG_SYS_MAX_FLASH_SECT;
1736d33c6acSTsiChung Liew 	}
1746d33c6acSTsiChung Liew 
1756d33c6acSTsiChung Liew 	return (info->size);
1766d33c6acSTsiChung Liew }
1776d33c6acSTsiChung Liew 
flash_erase(flash_info_t * info,int s_first,int s_last)1786d33c6acSTsiChung Liew int flash_erase(flash_info_t * info, int s_first, int s_last)
1796d33c6acSTsiChung Liew {
1806d33c6acSTsiChung Liew 	FPWV *addr;
1816d33c6acSTsiChung Liew 	int flag, prot, sect, count;
182e6af3859SMasahiro Yamada 	ulong type, start;
1836d33c6acSTsiChung Liew 	int rcode = 0, flashtype = 0;
1846d33c6acSTsiChung Liew 
1856d33c6acSTsiChung Liew 	if ((s_first < 0) || (s_first > s_last)) {
1866d33c6acSTsiChung Liew 		if (info->flash_id == FLASH_UNKNOWN)
1876d33c6acSTsiChung Liew 			printf("- missing\n");
1886d33c6acSTsiChung Liew 		else
1896d33c6acSTsiChung Liew 			printf("- no sectors to erase\n");
1906d33c6acSTsiChung Liew 		return 1;
1916d33c6acSTsiChung Liew 	}
1926d33c6acSTsiChung Liew 
1936d33c6acSTsiChung Liew 	type = (info->flash_id & FLASH_VENDMASK);
1946d33c6acSTsiChung Liew 
1956d33c6acSTsiChung Liew 	switch (type) {
1966d33c6acSTsiChung Liew 	case FLASH_MAN_SST:
1976d33c6acSTsiChung Liew 		flashtype = 1;
1986d33c6acSTsiChung Liew 		break;
1996d33c6acSTsiChung Liew 	default:
2006d33c6acSTsiChung Liew 		type = (info->flash_id & FLASH_VENDMASK);
2016d33c6acSTsiChung Liew 		printf("Can't erase unknown flash type %08lx - aborted\n",
2026d33c6acSTsiChung Liew 		       info->flash_id);
2036d33c6acSTsiChung Liew 		return 1;
2046d33c6acSTsiChung Liew 	}
2056d33c6acSTsiChung Liew 
2066d33c6acSTsiChung Liew 	prot = 0;
2076d33c6acSTsiChung Liew 	for (sect = s_first; sect <= s_last; ++sect) {
2086d33c6acSTsiChung Liew 		if (info->protect[sect]) {
2096d33c6acSTsiChung Liew 			prot++;
2106d33c6acSTsiChung Liew 		}
2116d33c6acSTsiChung Liew 	}
2126d33c6acSTsiChung Liew 
2136d33c6acSTsiChung Liew 	if (prot)
2146d33c6acSTsiChung Liew 		printf("- Warning: %d protected sectors will not be erased!\n",
2156d33c6acSTsiChung Liew 		       prot);
2166d33c6acSTsiChung Liew 	else
2176d33c6acSTsiChung Liew 		printf("\n");
2186d33c6acSTsiChung Liew 
2196d33c6acSTsiChung Liew 	flag = disable_interrupts();
2206d33c6acSTsiChung Liew 
2216d33c6acSTsiChung Liew 	start = get_timer(0);
2226d33c6acSTsiChung Liew 
2236d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 	if ((s_last - s_first) == (CONFIG_SYS_SST_SECT - 1)) {
2246d33c6acSTsiChung Liew 		if (prot == 0) {
2256d33c6acSTsiChung Liew 			addr = (FPWV *) info->start[0];
2266d33c6acSTsiChung Liew 
2276d33c6acSTsiChung Liew 			addr[FLASH_CYCLE1] = 0x00AA;	/* unlock */
2286d33c6acSTsiChung Liew 			addr[FLASH_CYCLE2] = 0x0055;	/* unlock */
2296d33c6acSTsiChung Liew 			addr[FLASH_CYCLE1] = 0x0080;	/* erase mode */
2306d33c6acSTsiChung Liew 			addr[FLASH_CYCLE1] = 0x00AA;	/* unlock */
2316d33c6acSTsiChung Liew 			addr[FLASH_CYCLE2] = 0x0055;	/* unlock */
2326d33c6acSTsiChung Liew 			*addr = 0x0030;	/* erase chip */
2336d33c6acSTsiChung Liew 
2346d33c6acSTsiChung Liew 			count = 0;
2356d33c6acSTsiChung Liew 			start = get_timer(0);
2366d33c6acSTsiChung Liew 
2376d33c6acSTsiChung Liew 			while ((*addr & 0x0080) != 0x0080) {
2386d33c6acSTsiChung Liew 				if (count++ > 0x10000) {
2396d33c6acSTsiChung Liew 					spin_wheel();
2406d33c6acSTsiChung Liew 					count = 0;
2416d33c6acSTsiChung Liew 				}
2426d33c6acSTsiChung Liew 
2436d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 				if (get_timer(start) > CONFIG_SYS_FLASH_ERASE_TOUT) {
2446d33c6acSTsiChung Liew 					printf("Timeout\n");
2456d33c6acSTsiChung Liew 					*addr = 0x00F0;	/* reset to read mode */
2466d33c6acSTsiChung Liew 
2476d33c6acSTsiChung Liew 					return 1;
2486d33c6acSTsiChung Liew 				}
2496d33c6acSTsiChung Liew 			}
2506d33c6acSTsiChung Liew 
2516d33c6acSTsiChung Liew 			*addr = 0x00F0;	/* reset to read mode */
2526d33c6acSTsiChung Liew 
2536d33c6acSTsiChung Liew 			printf("\b. done\n");
2546d33c6acSTsiChung Liew 
2556d33c6acSTsiChung Liew 			if (flag)
2566d33c6acSTsiChung Liew 				enable_interrupts();
2576d33c6acSTsiChung Liew 
2586d33c6acSTsiChung Liew 			return 0;
2596d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 		} else if (prot == CONFIG_SYS_SST_SECT) {
2606d33c6acSTsiChung Liew 			return 1;
2616d33c6acSTsiChung Liew 		}
2626d33c6acSTsiChung Liew 	}
2636d33c6acSTsiChung Liew 
2646d33c6acSTsiChung Liew 	/* Start erase on unprotected sectors */
2656d33c6acSTsiChung Liew 	for (sect = s_first; sect <= s_last; sect++) {
2666d33c6acSTsiChung Liew 		if (info->protect[sect] == 0) {	/* not protected */
2676d33c6acSTsiChung Liew 
2686d33c6acSTsiChung Liew 			addr = (FPWV *) (info->start[sect]);
2696d33c6acSTsiChung Liew 
2706d33c6acSTsiChung Liew 			printf(".");
2716d33c6acSTsiChung Liew 
2726d33c6acSTsiChung Liew 			/* arm simple, non interrupt dependent timer */
2736d33c6acSTsiChung Liew 			start = get_timer(0);
2746d33c6acSTsiChung Liew 
2756d33c6acSTsiChung Liew 			switch (flashtype) {
2766d33c6acSTsiChung Liew 			case 1:
2776d33c6acSTsiChung Liew 				{
2786d33c6acSTsiChung Liew 					FPWV *base;	/* first address in bank */
2796d33c6acSTsiChung Liew 
2806d33c6acSTsiChung Liew 					flag = disable_interrupts();
2816d33c6acSTsiChung Liew 
2826d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 					base = (FPWV *) (CONFIG_SYS_FLASH_BASE);	/* First sector */
2836d33c6acSTsiChung Liew 
2846d33c6acSTsiChung Liew 					base[FLASH_CYCLE1] = 0x00AA;	/* unlock */
2856d33c6acSTsiChung Liew 					base[FLASH_CYCLE2] = 0x0055;	/* unlock */
2866d33c6acSTsiChung Liew 					base[FLASH_CYCLE1] = 0x0080;	/* erase mode */
2876d33c6acSTsiChung Liew 					base[FLASH_CYCLE1] = 0x00AA;	/* unlock */
2886d33c6acSTsiChung Liew 					base[FLASH_CYCLE2] = 0x0055;	/* unlock */
2896d33c6acSTsiChung Liew 					*addr = 0x0050;	/* erase sector */
2906d33c6acSTsiChung Liew 
2916d33c6acSTsiChung Liew 					if (flag)
2926d33c6acSTsiChung Liew 						enable_interrupts();
2936d33c6acSTsiChung Liew 
2946d33c6acSTsiChung Liew 					while ((*addr & 0x0080) != 0x0080) {
2956d33c6acSTsiChung Liew 						if (get_timer(start) >
2966d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 						    CONFIG_SYS_FLASH_ERASE_TOUT) {
2976d33c6acSTsiChung Liew 							printf("Timeout\n");
2986d33c6acSTsiChung Liew 							*addr = 0x00F0;	/* reset to read mode */
2996d33c6acSTsiChung Liew 
3006d33c6acSTsiChung Liew 							rcode = 1;
3016d33c6acSTsiChung Liew 							break;
3026d33c6acSTsiChung Liew 						}
3036d33c6acSTsiChung Liew 					}
3046d33c6acSTsiChung Liew 
3056d33c6acSTsiChung Liew 					*addr = 0x00F0;	/* reset to read mode */
3066d33c6acSTsiChung Liew 					break;
3076d33c6acSTsiChung Liew 				}
3086d33c6acSTsiChung Liew 			}	/* switch (flashtype) */
3096d33c6acSTsiChung Liew 		}
3106d33c6acSTsiChung Liew 	}
3116d33c6acSTsiChung Liew 	printf(" done\n");
3126d33c6acSTsiChung Liew 
3136d33c6acSTsiChung Liew 	if (flag)
3146d33c6acSTsiChung Liew 		enable_interrupts();
3156d33c6acSTsiChung Liew 
3166d33c6acSTsiChung Liew 	return rcode;
3176d33c6acSTsiChung Liew }
3186d33c6acSTsiChung Liew 
write_buff(flash_info_t * info,uchar * src,ulong addr,ulong cnt)3196d33c6acSTsiChung Liew int write_buff(flash_info_t * info, uchar * src, ulong addr, ulong cnt)
3206d33c6acSTsiChung Liew {
3216d33c6acSTsiChung Liew 	ulong wp, count;
3226d33c6acSTsiChung Liew 	u16 data;
323e6af3859SMasahiro Yamada 	int rc;
3246d33c6acSTsiChung Liew 
3256d33c6acSTsiChung Liew 	if (info->flash_id == FLASH_UNKNOWN)
3266d33c6acSTsiChung Liew 		return 4;
3276d33c6acSTsiChung Liew 
3286d33c6acSTsiChung Liew 	/* get lower word aligned address */
3296d33c6acSTsiChung Liew 	wp = addr;
3306d33c6acSTsiChung Liew 
3316d33c6acSTsiChung Liew 	/* handle unaligned start bytes */
3326d33c6acSTsiChung Liew 	if (wp & 1) {
3336d33c6acSTsiChung Liew 		data = *((FPWV *) wp);
3346d33c6acSTsiChung Liew 		data = (data << 8) | *src;
3356d33c6acSTsiChung Liew 
3366d33c6acSTsiChung Liew 		if ((rc = write_word(info, (FPWV *) wp, data)) != 0)
3376d33c6acSTsiChung Liew 			return (rc);
3386d33c6acSTsiChung Liew 
3396d33c6acSTsiChung Liew 		wp++;
3406d33c6acSTsiChung Liew 		cnt -= 1;
3416d33c6acSTsiChung Liew 		src++;
3426d33c6acSTsiChung Liew 	}
3436d33c6acSTsiChung Liew 
3446d33c6acSTsiChung Liew 	while (cnt >= 2) {
3456d33c6acSTsiChung Liew 		/*
3466d33c6acSTsiChung Liew 		 * handle word aligned part
3476d33c6acSTsiChung Liew 		 */
3486d33c6acSTsiChung Liew 		count = 0;
3496d33c6acSTsiChung Liew 		data = *((FPWV *) src);
3506d33c6acSTsiChung Liew 
3516d33c6acSTsiChung Liew 		if ((rc = write_word(info, (FPWV *) wp, data)) != 0)
3526d33c6acSTsiChung Liew 			return (rc);
3536d33c6acSTsiChung Liew 
3546d33c6acSTsiChung Liew 		wp += 2;
3556d33c6acSTsiChung Liew 		src += 2;
3566d33c6acSTsiChung Liew 		cnt -= 2;
3576d33c6acSTsiChung Liew 
3586d33c6acSTsiChung Liew 		if (count++ > 0x800) {
3596d33c6acSTsiChung Liew 			spin_wheel();
3606d33c6acSTsiChung Liew 			count = 0;
3616d33c6acSTsiChung Liew 		}
3626d33c6acSTsiChung Liew 	}
3636d33c6acSTsiChung Liew 	/* handle word aligned part */
3646d33c6acSTsiChung Liew 	if (cnt) {
3656d33c6acSTsiChung Liew 		/* handle word aligned part */
3666d33c6acSTsiChung Liew 		count = 0;
3676d33c6acSTsiChung Liew 		data = *((FPWV *) wp);
3686d33c6acSTsiChung Liew 
3696d33c6acSTsiChung Liew 		data = (data & 0x00FF) | (*src << 8);
3706d33c6acSTsiChung Liew 
3716d33c6acSTsiChung Liew 		if ((rc = write_word(info, (FPWV *) wp, data)) != 0)
3726d33c6acSTsiChung Liew 			return (rc);
3736d33c6acSTsiChung Liew 
3746d33c6acSTsiChung Liew 		wp++;
3756d33c6acSTsiChung Liew 		src++;
3766d33c6acSTsiChung Liew 		cnt -= 1;
3776d33c6acSTsiChung Liew 		if (count++ > 0x800) {
3786d33c6acSTsiChung Liew 			spin_wheel();
3796d33c6acSTsiChung Liew 			count = 0;
3806d33c6acSTsiChung Liew 		}
3816d33c6acSTsiChung Liew 	}
3826d33c6acSTsiChung Liew 
3836d33c6acSTsiChung Liew 	if (cnt == 0)
3846d33c6acSTsiChung Liew 		return ERR_OK;
3856d33c6acSTsiChung Liew 
3866d33c6acSTsiChung Liew 	return ERR_OK;
3876d33c6acSTsiChung Liew }
3886d33c6acSTsiChung Liew 
3896d33c6acSTsiChung Liew /*-----------------------------------------------------------------------
3906d33c6acSTsiChung Liew  * Write a word to Flash
3916d33c6acSTsiChung Liew  * A word is 16 bits, whichever the bus width of the flash bank
3926d33c6acSTsiChung Liew  * (not an individual chip) is.
3936d33c6acSTsiChung Liew  *
3946d33c6acSTsiChung Liew  * returns:
3956d33c6acSTsiChung Liew  * 0 - OK
3966d33c6acSTsiChung Liew  * 1 - write timeout
3976d33c6acSTsiChung Liew  * 2 - Flash not erased
3986d33c6acSTsiChung Liew  */
write_word(flash_info_t * info,FPWV * dest,u16 data)3996d33c6acSTsiChung Liew int write_word(flash_info_t * info, FPWV * dest, u16 data)
4006d33c6acSTsiChung Liew {
4016d33c6acSTsiChung Liew 	ulong start;
4026d33c6acSTsiChung Liew 	int flag;
4036d33c6acSTsiChung Liew 	int res = 0;		/* result, assume success */
4046d33c6acSTsiChung Liew 	FPWV *base;		/* first address in flash bank */
4056d33c6acSTsiChung Liew 
4066d33c6acSTsiChung Liew 	/* Check if Flash is (sufficiently) erased */
4076d33c6acSTsiChung Liew 	if ((*dest & (u8) data) != (u8) data) {
4086d33c6acSTsiChung Liew 		return (2);
4096d33c6acSTsiChung Liew 	}
4106d33c6acSTsiChung Liew 
4116d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 	base = (FPWV *) (CONFIG_SYS_FLASH_BASE);
4126d33c6acSTsiChung Liew 
4136d33c6acSTsiChung Liew 	/* Disable interrupts which might cause a timeout here */
4146d33c6acSTsiChung Liew 	flag = disable_interrupts();
4156d33c6acSTsiChung Liew 
4166d33c6acSTsiChung Liew 	base[FLASH_CYCLE1] = (u8) 0x00AA00AA;	/* unlock */
4176d33c6acSTsiChung Liew 	base[FLASH_CYCLE2] = (u8) 0x00550055;	/* unlock */
4186d33c6acSTsiChung Liew 	base[FLASH_CYCLE1] = (u8) 0x00A000A0;	/* selects program mode */
4196d33c6acSTsiChung Liew 
4206d33c6acSTsiChung Liew 	*dest = data;		/* start programming the data */
4216d33c6acSTsiChung Liew 
4226d33c6acSTsiChung Liew 	/* re-enable interrupts if necessary */
4236d33c6acSTsiChung Liew 	if (flag)
4246d33c6acSTsiChung Liew 		enable_interrupts();
4256d33c6acSTsiChung Liew 
4266d33c6acSTsiChung Liew 	start = get_timer(0);
4276d33c6acSTsiChung Liew 
4286d33c6acSTsiChung Liew 	/* data polling for D7 */
4296d33c6acSTsiChung Liew 	while (res == 0
4306d33c6acSTsiChung Liew 	       && (*dest & (u8) 0x00800080) != (data & (u8) 0x00800080)) {
4316d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 		if (get_timer(start) > CONFIG_SYS_FLASH_WRITE_TOUT) {
4326d33c6acSTsiChung Liew 			*dest = (u8) 0x00F000F0;	/* reset bank */
4336d33c6acSTsiChung Liew 			res = 1;
4346d33c6acSTsiChung Liew 		}
4356d33c6acSTsiChung Liew 	}
4366d33c6acSTsiChung Liew 
4376d33c6acSTsiChung Liew 	*dest++ = (u8) 0x00F000F0;	/* reset bank */
4386d33c6acSTsiChung Liew 
4396d33c6acSTsiChung Liew 	return (res);
4406d33c6acSTsiChung Liew }
4416d33c6acSTsiChung Liew 
spin_wheel(void)442*b411f2afSTom Rini static inline void spin_wheel(void)
4436d33c6acSTsiChung Liew {
4446d33c6acSTsiChung Liew 	static int p = 0;
4456d33c6acSTsiChung Liew 	static char w[] = "\\/-";
4466d33c6acSTsiChung Liew 
4476d33c6acSTsiChung Liew 	printf("\010%c", w[p]);
4486d33c6acSTsiChung Liew 	(++p == 3) ? (p = 0) : 0;
4496d33c6acSTsiChung Liew }
4506d33c6acSTsiChung Liew 
4516d33c6acSTsiChung Liew #endif
452