Ejemplo n.º 1
0
static int mrvlqspi_flash_write(struct flash_bank *bank, const uint8_t *buffer,
	uint32_t offset, uint32_t count)
{
	struct target *target = bank->target;
	struct mrvlqspi_flash_bank *mrvlqspi_info = bank->driver_priv;
	int retval = ERROR_OK;
	uint32_t page_size, fifo_size;
	struct working_area *fifo;
	struct reg_param reg_params[6];
	struct armv7m_algorithm armv7m_info;
	struct working_area *write_algorithm;
	int sector;

	LOG_DEBUG("offset=0x%08" PRIx32 " count=0x%08" PRIx32,
		offset, count);

	if (target->state != TARGET_HALTED) {
		LOG_ERROR("Target not halted");
		return ERROR_TARGET_NOT_HALTED;
	}

	if (offset + count > mrvlqspi_info->dev->size_in_bytes) {
		LOG_WARNING("Writes past end of flash. Extra data discarded.");
		count = mrvlqspi_info->dev->size_in_bytes - offset;
	}

	/* Check sector protection */
	for (sector = 0; sector < bank->num_sectors; sector++) {
		/* Start offset in or before this sector? */
		/* End offset in or behind this sector? */
		if ((offset <
			(bank->sectors[sector].offset + bank->sectors[sector].size))
			&& ((offset + count - 1) >= bank->sectors[sector].offset)
			&& bank->sectors[sector].is_protected) {
			LOG_ERROR("Flash sector %d protected", sector);
			return ERROR_FAIL;
		}
	}

	page_size = mrvlqspi_info->dev->pagesize;

	/* See contrib/loaders/flash/mrvlqspi.S for src */
	static const uint8_t mrvlqspi_flash_write_code[] = {
		0x4f, 0xf0, 0x00, 0x0a, 0xa2, 0x44, 0x92, 0x45,
		0x7f, 0xf6, 0xfc, 0xaf, 0x00, 0xf0, 0x6b, 0xf8,
		0x5f, 0xf0, 0x01, 0x08, 0xc5, 0xf8, 0x1c, 0x80,
		0x5f, 0xf0, 0x06, 0x08, 0xc5, 0xf8, 0x10, 0x80,
		0x5f, 0xf0, 0x01, 0x09, 0x00, 0xf0, 0x6b, 0xf8,
		0x00, 0xf0, 0x7d, 0xf8, 0x5f, 0xf0, 0x31, 0x08,
		0xc5, 0xf8, 0x1c, 0x80, 0x90, 0x46, 0xc5, 0xf8,
		0x14, 0x80, 0x5f, 0xf0, 0x02, 0x08, 0xc5, 0xf8,
		0x10, 0x80, 0x5f, 0xf0, 0x01, 0x09, 0x00, 0xf0,
		0x5a, 0xf8, 0xd0, 0xf8, 0x00, 0x80, 0xb8, 0xf1,
		0x00, 0x0f, 0x00, 0xf0, 0x8b, 0x80, 0x47, 0x68,
		0x47, 0x45, 0x3f, 0xf4, 0xf6, 0xaf, 0x17, 0xf8,
		0x01, 0x9b, 0x00, 0xf0, 0x30, 0xf8, 0x8f, 0x42,
		0x28, 0xbf, 0x00, 0xf1, 0x08, 0x07, 0x47, 0x60,
		0x01, 0x3b, 0x00, 0x2b, 0x00, 0xf0, 0x05, 0x80,
		0x02, 0xf1, 0x01, 0x02, 0x92, 0x45, 0x7f, 0xf4,
		0xe4, 0xaf, 0x00, 0xf0, 0x50, 0xf8, 0xa2, 0x44,
		0x00, 0xf0, 0x2d, 0xf8, 0x5f, 0xf0, 0x01, 0x08,
		0xc5, 0xf8, 0x1c, 0x80, 0x5f, 0xf0, 0x00, 0x08,
		0xc5, 0xf8, 0x20, 0x80, 0x5f, 0xf0, 0x05, 0x08,
		0xc5, 0xf8, 0x10, 0x80, 0x5f, 0xf0, 0x00, 0x09,
		0x00, 0xf0, 0x29, 0xf8, 0x00, 0xf0, 0x13, 0xf8,
		0x09, 0xf0, 0x01, 0x09, 0xb9, 0xf1, 0x00, 0x0f,
		0xf8, 0xd1, 0x00, 0xf0, 0x34, 0xf8, 0x00, 0x2b,
		0xa4, 0xd1, 0x00, 0xf0, 0x53, 0xb8, 0xd5, 0xf8,
		0x00, 0x80, 0x5f, 0xea, 0x08, 0x68, 0xfa, 0xd4,
		0xc5, 0xf8, 0x08, 0x90, 0x70, 0x47, 0xd5, 0xf8,
		0x00, 0x80, 0x5f, 0xea, 0xc8, 0x68, 0xfa, 0xd4,
		0xd5, 0xf8, 0x0c, 0x90, 0x70, 0x47, 0xd5, 0xf8,
		0x04, 0x80, 0x48, 0xf4, 0x00, 0x78, 0xc5, 0xf8,
		0x04, 0x80, 0xd5, 0xf8, 0x04, 0x80, 0x5f, 0xea,
		0x88, 0x58, 0xfa, 0xd4, 0x70, 0x47, 0xd5, 0xf8,
		0x00, 0x80, 0x48, 0xf0, 0x01, 0x08, 0xc5, 0xf8,
		0x00, 0x80, 0xd5, 0xf8, 0x00, 0x80, 0x5f, 0xea,
		0x88, 0x78, 0xfa, 0xd5, 0xd5, 0xf8, 0x04, 0x80,
		0x69, 0xf3, 0x4d, 0x38, 0x48, 0xf4, 0x00, 0x48,
		0xc5, 0xf8, 0x04, 0x80, 0x70, 0x47, 0xd5, 0xf8,
		0x00, 0x80, 0x5f, 0xea, 0x88, 0x78, 0xfa, 0xd5,
		0xd5, 0xf8, 0x00, 0x80, 0x5f, 0xea, 0x48, 0x68,
		0xfa, 0xd5, 0xd5, 0xf8, 0x04, 0x80, 0x48, 0xf4,
		0x80, 0x48, 0xc5, 0xf8, 0x04, 0x80, 0xd5, 0xf8,
		0x04, 0x80, 0x5f, 0xea, 0x08, 0x48, 0xfa, 0xd4,
		0xd5, 0xf8, 0x00, 0x80, 0x28, 0xf0, 0x01, 0x08,
		0xc5, 0xf8, 0x00, 0x80, 0xd5, 0xf8, 0x00, 0x80,
		0x5f, 0xea, 0x88, 0x78, 0xfa, 0xd5, 0x70, 0x47,
		0x00, 0x20, 0x50, 0x60, 0x30, 0x46, 0x00, 0xbe
	};

	if (target_alloc_working_area(target, sizeof(mrvlqspi_flash_write_code),
			&write_algorithm) != ERROR_OK) {
		LOG_ERROR("Insufficient working area. You must configure"\
			" a working area > %zdB in order to write to SPIFI flash.",
			sizeof(mrvlqspi_flash_write_code));
		return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
	}

	retval = target_write_buffer(target, write_algorithm->address,
			sizeof(mrvlqspi_flash_write_code),
			mrvlqspi_flash_write_code);
	if (retval != ERROR_OK) {
		target_free_working_area(target, write_algorithm);
		return retval;
	}

	/* FIFO allocation */
	fifo_size = target_get_working_area_avail(target);

	if (fifo_size == 0) {
		/* if we already allocated the writing code but failed to get fifo
		 * space, free the algorithm */
		target_free_working_area(target, write_algorithm);

		LOG_ERROR("Insufficient working area. Please allocate at least"\
			" %zdB of working area to enable flash writes.",
			sizeof(mrvlqspi_flash_write_code) + 1
		);

		return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
	} else if (fifo_size < page_size)
		LOG_WARNING("Working area size is limited; flash writes may be"\
			" slow. Increase working area size to at least %zdB"\
			" to reduce write times.",
			(size_t)(sizeof(mrvlqspi_flash_write_code) + page_size)
		);

	if (target_alloc_working_area(target, fifo_size, &fifo) != ERROR_OK) {
		target_free_working_area(target, write_algorithm);
		return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
	}

	armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
	armv7m_info.core_mode = ARM_MODE_THREAD;

	init_reg_param(&reg_params[0], "r0", 32, PARAM_IN_OUT);	/* buffer start, status (out) */
	init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);	/* buffer end */
	init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);	/* target address */
	init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT);	/* count (halfword-16bit) */
	init_reg_param(&reg_params[4], "r4", 32, PARAM_OUT);	/* page size */
	init_reg_param(&reg_params[5], "r5", 32, PARAM_OUT);	/* qspi base address */

	buf_set_u32(reg_params[0].value, 0, 32, fifo->address);
	buf_set_u32(reg_params[1].value, 0, 32, fifo->address + fifo->size);
	buf_set_u32(reg_params[2].value, 0, 32, offset);
	buf_set_u32(reg_params[3].value, 0, 32, count);
	buf_set_u32(reg_params[4].value, 0, 32, page_size);
	buf_set_u32(reg_params[5].value, 0, 32, (uint32_t) mrvlqspi_info->reg_base);

	retval = target_run_flash_async_algorithm(target, buffer, count, 1,
			0, NULL,
			6, reg_params,
			fifo->address, fifo->size,
			write_algorithm->address, 0,
			&armv7m_info
	);

	if (retval != ERROR_OK)
		LOG_ERROR("Error executing flash write algorithm");

	target_free_working_area(target, fifo);
	target_free_working_area(target, write_algorithm);

	destroy_reg_param(&reg_params[0]);
	destroy_reg_param(&reg_params[1]);
	destroy_reg_param(&reg_params[2]);
	destroy_reg_param(&reg_params[3]);
	destroy_reg_param(&reg_params[4]);
	destroy_reg_param(&reg_params[5]);

	return retval;
}
Ejemplo n.º 2
0
static int lpcspifi_write(struct flash_bank *bank, uint8_t *buffer,
	uint32_t offset, uint32_t count)
{
	struct target *target = bank->target;
	struct lpcspifi_flash_bank *lpcspifi_info = bank->driver_priv;
	uint32_t page_size, fifo_size;
	struct working_area *fifo;
	struct reg_param reg_params[5];
	struct armv7m_algorithm armv7m_info;
	struct working_area *write_algorithm;
	int sector;
	int retval = ERROR_OK;

	LOG_DEBUG("offset=0x%08" PRIx32 " count=0x%08" PRIx32,
		offset, count);

	if (target->state != TARGET_HALTED) {
		LOG_ERROR("Target not halted");
		return ERROR_TARGET_NOT_HALTED;
	}

	if (offset + count > lpcspifi_info->dev->size_in_bytes) {
		LOG_WARNING("Writes past end of flash. Extra data discarded.");
		count = lpcspifi_info->dev->size_in_bytes - offset;
	}

	/* Check sector protection */
	for (sector = 0; sector < bank->num_sectors; sector++) {
		/* Start offset in or before this sector? */
		/* End offset in or behind this sector? */
		if ((offset <
				(bank->sectors[sector].offset + bank->sectors[sector].size))
			&& ((offset + count - 1) >= bank->sectors[sector].offset)
			&& bank->sectors[sector].is_protected) {
			LOG_ERROR("Flash sector %d protected", sector);
			return ERROR_FAIL;
		}
	}

	page_size = lpcspifi_info->dev->pagesize;

	retval = lpcspifi_set_hw_mode(bank);
	if (retval != ERROR_OK)
		return retval;

	/* see contrib/loaders/flash/lpcspifi_write.S for src */
	static const uint8_t lpcspifi_flash_write_code[] = {
		0x4f, 0xf4, 0xc0, 0x4a, 0xc4, 0xf2, 0x08, 0x0a,
		0x4f, 0xf0, 0xea, 0x08, 0xca, 0xf8, 0x8c, 0x81,
		0x4f, 0xf0, 0x40, 0x08, 0xca, 0xf8, 0x90, 0x81,
		0x4f, 0xf0, 0x40, 0x08, 0xca, 0xf8, 0x94, 0x81,
		0x4f, 0xf0, 0xed, 0x08, 0xca, 0xf8, 0x98, 0x81,
		0x4f, 0xf0, 0xed, 0x08, 0xca, 0xf8, 0x9c, 0x81,
		0x4f, 0xf0, 0x44, 0x08, 0xca, 0xf8, 0xa0, 0x81,
		0x4f, 0xf4, 0xc0, 0x4a, 0xc4, 0xf2, 0x0f, 0x0a,
		0x4f, 0xf4, 0x00, 0x68, 0xca, 0xf8, 0x14, 0x80,
		0x4f, 0xf4, 0x80, 0x4a, 0xc4, 0xf2, 0x0f, 0x0a,
		0x4f, 0xf0, 0xff, 0x08, 0xca, 0xf8, 0xab, 0x80,
		0x4f, 0xf0, 0x00, 0x0a, 0xc4, 0xf2, 0x05, 0x0a,
		0x4f, 0xf0, 0x00, 0x08, 0xc0, 0xf2, 0x00, 0x18,
		0xca, 0xf8, 0x94, 0x80, 0x4f, 0xf4, 0x00, 0x5a,
		0xc4, 0xf2, 0x05, 0x0a, 0x4f, 0xf0, 0x01, 0x08,
		0xca, 0xf8, 0x00, 0x87, 0x4f, 0xf4, 0x40, 0x5a,
		0xc4, 0xf2, 0x08, 0x0a, 0x4f, 0xf0, 0x07, 0x08,
		0xca, 0xf8, 0x00, 0x80, 0x4f, 0xf0, 0x02, 0x08,
		0xca, 0xf8, 0x10, 0x80, 0xca, 0xf8, 0x04, 0x80,
		0x4f, 0xf0, 0x00, 0x0b, 0xa3, 0x44, 0x93, 0x45,
		0x7f, 0xf6, 0xfc, 0xaf, 0x00, 0xf0, 0x6a, 0xf8,
		0x4f, 0xf0, 0x06, 0x09, 0x00, 0xf0, 0x53, 0xf8,
		0x00, 0xf0, 0x60, 0xf8, 0x00, 0xf0, 0x62, 0xf8,
		0x4f, 0xf0, 0x05, 0x09, 0x00, 0xf0, 0x4b, 0xf8,
		0x4f, 0xf0, 0x00, 0x09, 0x00, 0xf0, 0x47, 0xf8,
		0x00, 0xf0, 0x54, 0xf8, 0x19, 0xf0, 0x02, 0x0f,
		0x00, 0xf0, 0x5d, 0x80, 0x00, 0xf0, 0x52, 0xf8,
		0x4f, 0xf0, 0x02, 0x09, 0x00, 0xf0, 0x3b, 0xf8,
		0x4f, 0xea, 0x12, 0x49, 0x00, 0xf0, 0x37, 0xf8,
		0x4f, 0xea, 0x12, 0x29, 0x00, 0xf0, 0x33, 0xf8,
		0x4f, 0xea, 0x02, 0x09, 0x00, 0xf0, 0x2f, 0xf8,
		0xd0, 0xf8, 0x00, 0x80, 0xb8, 0xf1, 0x00, 0x0f,
		0x00, 0xf0, 0x47, 0x80, 0x47, 0x68, 0x47, 0x45,
		0x3f, 0xf4, 0xf6, 0xaf, 0x17, 0xf8, 0x01, 0x9b,
		0x00, 0xf0, 0x21, 0xf8, 0x8f, 0x42, 0x28, 0xbf,
		0x00, 0xf1, 0x08, 0x07, 0x47, 0x60, 0x01, 0x3b,
		0xbb, 0xb3, 0x02, 0xf1, 0x01, 0x02, 0x93, 0x45,
		0x7f, 0xf4, 0xe6, 0xaf, 0x00, 0xf0, 0x22, 0xf8,
		0xa3, 0x44, 0x00, 0xf0, 0x23, 0xf8, 0x4f, 0xf0,
		0x05, 0x09, 0x00, 0xf0, 0x0c, 0xf8, 0x4f, 0xf0,
		0x00, 0x09, 0x00, 0xf0, 0x08, 0xf8, 0x00, 0xf0,
		0x15, 0xf8, 0x19, 0xf0, 0x01, 0x0f, 0x7f, 0xf4,
		0xf0, 0xaf, 0xff, 0xf7, 0xa7, 0xbf, 0x4f, 0xf4,
		0x40, 0x5a, 0xc4, 0xf2, 0x08, 0x0a, 0xca, 0xf8,
		0x08, 0x90, 0xda, 0xf8, 0x0c, 0x90, 0x19, 0xf0,
		0x10, 0x0f, 0x7f, 0xf4, 0xfa, 0xaf, 0xda, 0xf8,
		0x08, 0x90, 0x70, 0x47, 0x4f, 0xf0, 0xff, 0x08,
		0x00, 0xf0, 0x02, 0xb8, 0x4f, 0xf0, 0x00, 0x08,
		0x4f, 0xf4, 0x80, 0x4a, 0xc4, 0xf2, 0x0f, 0x0a,
		0xca, 0xf8, 0xab, 0x80, 0x70, 0x47, 0x00, 0x20,
		0x50, 0x60, 0x30, 0x46, 0x00, 0xbe, 0xff, 0xff
	};

	if (target_alloc_working_area(target, sizeof(lpcspifi_flash_write_code),
			&write_algorithm) != ERROR_OK) {
		LOG_ERROR("Insufficient working area. You must configure"\
			" a working area > %zdB in order to write to SPIFI flash.",
			sizeof(lpcspifi_flash_write_code));
		return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
	};

	retval = target_write_buffer(target, write_algorithm->address,
			sizeof(lpcspifi_flash_write_code),
			lpcspifi_flash_write_code);
	if (retval != ERROR_OK) {
		target_free_working_area(target, write_algorithm);
		return retval;
	}

	/* FIFO allocation */
	fifo_size = target_get_working_area_avail(target);

	if (fifo_size == 0) {
		/* if we already allocated the writing code but failed to get fifo
		 * space, free the algorithm */
		target_free_working_area(target, write_algorithm);

		LOG_ERROR("Insufficient working area. Please allocate at least"\
			" %zdB of working area to enable flash writes.",
			sizeof(lpcspifi_flash_write_code) + 1
		);

		return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
	} else if (fifo_size < page_size)
		LOG_WARNING("Working area size is limited; flash writes may be"\
			" slow. Increase working area size to at least %zdB"\
			" to reduce write times.",
			(size_t)(sizeof(lpcspifi_flash_write_code) + page_size)
		);
	else if (fifo_size > 0x2000) /* Beyond this point, we start to get diminishing returns */
		fifo_size = 0x2000;

	if (target_alloc_working_area(target, fifo_size, &fifo) != ERROR_OK) {
		target_free_working_area(target, write_algorithm);
		return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
	};

	armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
	armv7m_info.core_mode = ARM_MODE_THREAD;

	init_reg_param(&reg_params[0], "r0", 32, PARAM_IN_OUT);		/* buffer start, status (out) */
	init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);		/* buffer end */
	init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);		/* target address */
	init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT);		/* count (halfword-16bit) */
	init_reg_param(&reg_params[4], "r4", 32, PARAM_OUT);		/* page size */

	buf_set_u32(reg_params[0].value, 0, 32, fifo->address);
	buf_set_u32(reg_params[1].value, 0, 32, fifo->address + fifo->size);
	buf_set_u32(reg_params[2].value, 0, 32, offset);
	buf_set_u32(reg_params[3].value, 0, 32, count);
	buf_set_u32(reg_params[4].value, 0, 32, page_size);

	retval = target_run_flash_async_algorithm(target, buffer, count, 1,
			0, NULL,
			5, reg_params,
			fifo->address, fifo->size,
			write_algorithm->address, 0,
			&armv7m_info
	);

	if (retval != ERROR_OK)
		LOG_ERROR("Error executing flash write algorithm");

	target_free_working_area(target, fifo);
	target_free_working_area(target, write_algorithm);

	destroy_reg_param(&reg_params[0]);
	destroy_reg_param(&reg_params[1]);
	destroy_reg_param(&reg_params[2]);
	destroy_reg_param(&reg_params[3]);
	destroy_reg_param(&reg_params[4]);

	/* Switch to HW mode before return to prompt */
	retval = lpcspifi_set_hw_mode(bank);
	return retval;
}
Ejemplo n.º 3
0
/* Start a low level flash write for the specified region */
static int nrf5_ll_flash_write(struct nrf5_info *chip, uint32_t offset, const uint8_t *buffer, uint32_t bytes)
{
	struct target *target = chip->target;
	uint32_t buffer_size = 8192;
	struct working_area *write_algorithm;
	struct working_area *source;
	uint32_t address = NRF5_FLASH_BASE + offset;
	struct reg_param reg_params[4];
	struct armv7m_algorithm armv7m_info;
	int retval = ERROR_OK;


	LOG_DEBUG("Writing buffer to flash offset=0x%"PRIx32" bytes=0x%"PRIx32, offset, bytes);
	assert(bytes % 4 == 0);

	/* allocate working area with flash programming code */
	if (target_alloc_working_area(target, sizeof(nrf5_flash_write_code),
			&write_algorithm) != ERROR_OK) {
		LOG_WARNING("no working area available, falling back to slow memory writes");

		for (; bytes > 0; bytes -= 4) {
			retval = target_write_memory(chip->target, offset, 4, 1, buffer);
			if (retval != ERROR_OK)
				return retval;

			retval = nrf5_wait_for_nvmc(chip);
			if (retval != ERROR_OK)
				return retval;

			offset += 4;
			buffer += 4;
		}

		return ERROR_OK;
	}

	LOG_WARNING("using fast async flash loader. This is currently supported");
	LOG_WARNING("only with ST-Link and CMSIS-DAP. If you have issues, add");
	LOG_WARNING("\"set WORKAREASIZE 0\" before sourcing nrf51.cfg/nrf52.cfg to disable it");

	retval = target_write_buffer(target, write_algorithm->address,
				sizeof(nrf5_flash_write_code),
				nrf5_flash_write_code);
	if (retval != ERROR_OK)
		return retval;

	/* memory buffer */
	while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK) {
		buffer_size /= 2;
		buffer_size &= ~3UL; /* Make sure it's 4 byte aligned */
		if (buffer_size <= 256) {
			/* free working area, write algorithm already allocated */
			target_free_working_area(target, write_algorithm);

			LOG_WARNING("No large enough working area available, can't do block memory writes");
			return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
		}
	}

	armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
	armv7m_info.core_mode = ARM_MODE_THREAD;

	init_reg_param(&reg_params[0], "r0", 32, PARAM_IN_OUT);	/* byte count */
	init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);	/* buffer start */
	init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);	/* buffer end */
	init_reg_param(&reg_params[3], "r3", 32, PARAM_IN_OUT);	/* target address */

	buf_set_u32(reg_params[0].value, 0, 32, bytes);
	buf_set_u32(reg_params[1].value, 0, 32, source->address);
	buf_set_u32(reg_params[2].value, 0, 32, source->address + source->size);
	buf_set_u32(reg_params[3].value, 0, 32, address);

	retval = target_run_flash_async_algorithm(target, buffer, bytes/4, 4,
			0, NULL,
			4, reg_params,
			source->address, source->size,
			write_algorithm->address, 0,
			&armv7m_info);

	target_free_working_area(target, source);
	target_free_working_area(target, write_algorithm);

	destroy_reg_param(&reg_params[0]);
	destroy_reg_param(&reg_params[1]);
	destroy_reg_param(&reg_params[2]);
	destroy_reg_param(&reg_params[3]);

	return retval;
}