From e40f6380638ed3f7780b78ceb1411f8b7059a073 Mon Sep 17 00:00:00 2001
From: David Brownell <dbrownell@users.sourceforge.net>
Date: Fri, 18 Dec 2009 01:33:19 -0800
Subject: stellaris: update bulk flash writes

Try to right-size the SRAM buffers, by not:
 - using them for very small writes
 - giving up when a large buffer isn't available
 - allocating buffers much larger than their data

Also don't:
 - bother loading the code unless we allocate the writebuffer too
 - be so verbose with messaging:
    * be more concise
    * reduce importance (e.g. DEBUG not WARNING)
    * remove duplication

The minimum buffer size is something of a guess.  It's eight
times smaller than before, almost the same size as the code
being downloaded.  It probably deserves some tuning.

Also, note an erratum affecting flash protection on some chips;
and narrow many over-wide lines affected by the above changes.

Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
---
 src/flash/nor/stellaris.c | 65 ++++++++++++++++++++++++++++++++---------------
 1 file changed, 45 insertions(+), 20 deletions(-)

(limited to 'src/flash/nor')

diff --git a/src/flash/nor/stellaris.c b/src/flash/nor/stellaris.c
index 4183cba8..51fe677c 100644
--- a/src/flash/nor/stellaris.c
+++ b/src/flash/nor/stellaris.c
@@ -748,6 +748,8 @@ static int stellaris_protect(struct flash_bank *bank, int set, int first, int la
 	/* Write commit command */
 	/* REVISIT safety check, since this cannot be undone
 	 * except by the "Recover a locked device" procedure.
+	 * REVISIT DustDevil-A0 parts have an erratum making FMPPE commits
+	 * inadvisable ... it makes future mass erase operations fail.
 	 */
 	LOG_WARNING("Flash protection cannot be removed once commited, commit is NOT executed !");
 	/* target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_COMT); */
@@ -823,37 +825,47 @@ static int stellaris_write_block(struct flash_bank *bank,
 	struct armv7m_algorithm armv7m_info;
 	int retval = ERROR_OK;
 
+	/* power of two, and multiple of word size */
+	static const unsigned buf_min = 32;
+
+	/* for small buffers it's faster not to download an algorithm */
+	if (wcount < buf_min)
+		return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+
 	LOG_DEBUG("(bank=%p buffer=%p offset=%08" PRIx32 " wcount=%08" PRIx32 "",
 			bank, buffer, offset, wcount);
 
 	/* flash write code */
 	if (target_alloc_working_area(target, sizeof(stellaris_write_code), &write_algorithm) != ERROR_OK)
 	{
-		LOG_WARNING("no working area available, can't do block memory writes");
+		LOG_DEBUG("no working area for block memory writes");
 		return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
 	};
 
-	target_write_buffer(target, write_algorithm->address,
-			sizeof(stellaris_write_code),
-			(uint8_t *) stellaris_write_code);
+	/* plus a buffer big enough for this data */
+	if (wcount < buffer_size) {
+		buffer_size = wcount;
+		buffer_size += buf_min - 1;
+		buffer_size &= ~(buf_min - 1);
+	}
 
 	/* memory buffer */
 	while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK)
 	{
-		LOG_DEBUG("called target_alloc_working_area(target=%p buffer_size=%08" PRIx32 " source=%p)",
-				target, buffer_size, source);
 		buffer_size /= 2;
-		if (buffer_size <= 256)
+		if (buffer_size <= buf_min)
 		{
-			/* if we already allocated the writing code, but failed to get a buffer, free the algorithm */
-			if (write_algorithm)
-				target_free_working_area(target, write_algorithm);
-
-			LOG_WARNING("no large enough working area available, can't do block memory writes");
+			target_free_working_area(target, write_algorithm);
 			return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
 		}
+		LOG_DEBUG("retry target_alloc_working_area(%s, size=%u)",
+				target_name(target), (unsigned) buffer_size);
 	};
 
+	retval = target_write_buffer(target, write_algorithm->address,
+			sizeof(stellaris_write_code),
+			(uint8_t *) stellaris_write_code);
+
 	armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
 	armv7m_info.core_mode = ARMV7M_MODE_ANY;
 
@@ -870,11 +882,20 @@ static int stellaris_write_block(struct flash_bank *bank,
 		buf_set_u32(reg_params[0].value, 0, 32, source->address);
 		buf_set_u32(reg_params[1].value, 0, 32, address);
 		buf_set_u32(reg_params[2].value, 0, 32, 4*thisrun_count);
-		LOG_INFO("Algorithm flash write %" PRIi32 " words to 0x%" PRIx32 ", %" PRIi32 " remaining", thisrun_count, address, (wcount - thisrun_count));
-		LOG_DEBUG("Algorithm flash write %" PRIi32 " words to 0x%" PRIx32 ", %" PRIi32 " remaining", thisrun_count, address, (wcount - thisrun_count));
-		if ((retval = target_run_algorithm(target, 0, NULL, 3, reg_params, write_algorithm->address, write_algorithm->address + sizeof(stellaris_write_code)-10, 10000, &armv7m_info)) != ERROR_OK)
+		LOG_DEBUG("Algorithm flash write %u words to 0x%" PRIx32
+				", %u remaining",
+				(unsigned) thisrun_count, address,
+				(unsigned) (wcount - thisrun_count));
+		retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
+				write_algorithm->address,
+				write_algorithm->address +
+					sizeof(stellaris_write_code) - 10,
+				10000, &armv7m_info);
+		if (retval != ERROR_OK)
 		{
-			LOG_ERROR("error executing stellaris flash write algorithm");
+			LOG_ERROR("error %d executing stellaris "
+					"flash write algorithm",
+					retval);
 			retval = ERROR_FLASH_OPERATION_FAILED;
 			break;
 		}
@@ -884,6 +905,10 @@ static int stellaris_write_block(struct flash_bank *bank,
 		wcount -= thisrun_count;
 	}
 
+	/* REVISIT we could speed up writing multi-section images by
+	 * not freeing the initialized write_algorithm this way.
+	 */
+
 	target_free_working_area(target, write_algorithm);
 	target_free_working_area(target, source);
 
@@ -942,13 +967,13 @@ static int stellaris_write(struct flash_bank *bank, uint8_t *buffer, uint32_t of
 	if (words_remaining > 0)
 	{
 		/* try using a block write */
-		if ((retval = stellaris_write_block(bank, buffer, offset, words_remaining)) != ERROR_OK)
+		retval = stellaris_write_block(bank, buffer, offset,
+				words_remaining);
+		if (retval != ERROR_OK)
 		{
 			if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
 			{
-				/* if block write failed (no sufficient working area),
-				 * we use normal (slow) single dword accesses */
-				LOG_WARNING("couldn't use block writes, falling back to single memory accesses");
+				LOG_DEBUG("writing flash word-at-a-time");
 			}
 			else if (retval == ERROR_FLASH_OPERATION_FAILED)
 			{
-- 
cgit v1.2.3