Explorar o código

cfi_flash: Support buffered writes on non-standard Spansion NOR flash

Some NOR flash chip from Spansion, for example, the s29ws-n MirrorBit
series require different addresses for buffered write commands. Define a
configuration option to support buffered writes on those chips. A more
elegant solution would be to automatically detect those chips by parsing
their CFI records, but that would require introduction of a fixup table
into the cfi_flash driver.

Signed-off-by: Guennadi Liakhovetski <lg@denx.de>
Guennadi Liakhovetski %!s(int64=17) %!d(string=hai) anos
pai
achega
96ef831f71
Modificáronse 2 ficheiros con 23 adicións e 30 borrados
  1. 7 0
      README
  2. 16 30
      drivers/mtd/cfi_flash.c

+ 7 - 0
README

@@ -2040,6 +2040,13 @@ Configuration Settings:
 		This option also enables the building of the cfi_flash driver
 		This option also enables the building of the cfi_flash driver
 		in the drivers directory
 		in the drivers directory
 
 
+- CFG_FLASH_USE_BUFFER_WRITE
+		Use buffered writes to flash.
+
+- CONFIG_FLASH_SPANSION_S29WS_N
+		s29ws-n MirrorBit flash has non-standard addresses for buffered
+		write commands.
+
 - CFG_FLASH_QUIET_TEST
 - CFG_FLASH_QUIET_TEST
 		If this option is defined, the common CFI flash doesn't
 		If this option is defined, the common CFI flash doesn't
 		print it's warning upon not recognized FLASH banks. This
 		print it's warning upon not recognized FLASH banks. This

+ 16 - 30
drivers/mtd/cfi_flash.c

@@ -844,25 +844,29 @@ static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp,
 	void *dst = map_physmem(dest, len, MAP_NOCACHE);
 	void *dst = map_physmem(dest, len, MAP_NOCACHE);
 	void *dst2 = dst;
 	void *dst2 = dst;
 	int flag = 0;
 	int flag = 0;
+	uint offset = 0;
+	unsigned int shift;
 
 
 	switch (info->portwidth) {
 	switch (info->portwidth) {
 	case FLASH_CFI_8BIT:
 	case FLASH_CFI_8BIT:
-		cnt = len;
+		shift = 0;
 		break;
 		break;
 	case FLASH_CFI_16BIT:
 	case FLASH_CFI_16BIT:
-		cnt = len >> 1;
+		shift = 1;
 		break;
 		break;
 	case FLASH_CFI_32BIT:
 	case FLASH_CFI_32BIT:
-		cnt = len >> 2;
+		shift = 2;
 		break;
 		break;
 	case FLASH_CFI_64BIT:
 	case FLASH_CFI_64BIT:
-		cnt = len >> 3;
+		shift = 3;
 		break;
 		break;
 	default:
 	default:
 		retcode = ERR_INVAL;
 		retcode = ERR_INVAL;
 		goto out_unmap;
 		goto out_unmap;
 	}
 	}
 
 
+	cnt = len >> shift;
+
 	while ((cnt-- > 0) && (flag == 0)) {
 	while ((cnt-- > 0) && (flag == 0)) {
 		switch (info->portwidth) {
 		switch (info->portwidth) {
 		case FLASH_CFI_8BIT:
 		case FLASH_CFI_8BIT:
@@ -906,23 +910,7 @@ static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp,
 		if (retcode == ERR_OK) {
 		if (retcode == ERR_OK) {
 			/* reduce the number of loops by the width of
 			/* reduce the number of loops by the width of
 			 * the port */
 			 * the port */
-			switch (info->portwidth) {
-			case FLASH_CFI_8BIT:
-				cnt = len;
-				break;
-			case FLASH_CFI_16BIT:
-				cnt = len >> 1;
-				break;
-			case FLASH_CFI_32BIT:
-				cnt = len >> 2;
-				break;
-			case FLASH_CFI_64BIT:
-				cnt = len >> 3;
-				break;
-			default:
-				retcode = ERR_INVAL;
-				goto out_unmap;
-			}
+			cnt = len >> shift;
 			flash_write_cmd (info, sector, 0, (uchar) cnt - 1);
 			flash_write_cmd (info, sector, 0, (uchar) cnt - 1);
 			while (cnt-- > 0) {
 			while (cnt-- > 0) {
 				switch (info->portwidth) {
 				switch (info->portwidth) {
@@ -959,36 +947,34 @@ static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp,
 	case CFI_CMDSET_AMD_STANDARD:
 	case CFI_CMDSET_AMD_STANDARD:
 	case CFI_CMDSET_AMD_EXTENDED:
 	case CFI_CMDSET_AMD_EXTENDED:
 		flash_unlock_seq(info,0);
 		flash_unlock_seq(info,0);
-		flash_write_cmd (info, sector, 0, AMD_CMD_WRITE_TO_BUFFER);
+
+#ifdef CONFIG_FLASH_SPANSION_S29WS_N
+		offset = ((unsigned long)dst - info->start[sector]) >> shift;
+#endif
+		flash_write_cmd(info, sector, offset, AMD_CMD_WRITE_TO_BUFFER);
+		cnt = len >> shift;
+		flash_write_cmd(info, sector, offset, (uchar)cnt - 1);
 
 
 		switch (info->portwidth) {
 		switch (info->portwidth) {
 		case FLASH_CFI_8BIT:
 		case FLASH_CFI_8BIT:
-			cnt = len;
-			flash_write_cmd (info, sector, 0,  (uchar) cnt - 1);
 			while (cnt-- > 0) {
 			while (cnt-- > 0) {
 				flash_write8(flash_read8(src), dst);
 				flash_write8(flash_read8(src), dst);
 				src += 1, dst += 1;
 				src += 1, dst += 1;
 			}
 			}
 			break;
 			break;
 		case FLASH_CFI_16BIT:
 		case FLASH_CFI_16BIT:
-			cnt = len >> 1;
-			flash_write_cmd (info, sector, 0,  (uchar) cnt - 1);
 			while (cnt-- > 0) {
 			while (cnt-- > 0) {
 				flash_write16(flash_read16(src), dst);
 				flash_write16(flash_read16(src), dst);
 				src += 2, dst += 2;
 				src += 2, dst += 2;
 			}
 			}
 			break;
 			break;
 		case FLASH_CFI_32BIT:
 		case FLASH_CFI_32BIT:
-			cnt = len >> 2;
-			flash_write_cmd (info, sector, 0,  (uchar) cnt - 1);
 			while (cnt-- > 0) {
 			while (cnt-- > 0) {
 				flash_write32(flash_read32(src), dst);
 				flash_write32(flash_read32(src), dst);
 				src += 4, dst += 4;
 				src += 4, dst += 4;
 			}
 			}
 			break;
 			break;
 		case FLASH_CFI_64BIT:
 		case FLASH_CFI_64BIT:
-			cnt = len >> 3;
-			flash_write_cmd (info, sector, 0,  (uchar) cnt - 1);
 			while (cnt-- > 0) {
 			while (cnt-- > 0) {
 				flash_write64(flash_read64(src), dst);
 				flash_write64(flash_read64(src), dst);
 				src += 8, dst += 8;
 				src += 8, dst += 8;