* Dominic.Rath@gmx.de *
* Copyright (C) 2009 Michael Schwingen *
* michael@schwingen.org *
+ * Copyright (C) 2010 Øyvind Harboe <oyvind.harboe@zylin.com> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
{CFI_MFR_SST, 0x00D7, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_5555_2AAA]},
{CFI_MFR_SST, 0x2780, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_5555_2AAA]},
{CFI_MFR_ATMEL, 0x00C8, cfi_fixup_atmel_reversed_erase_regions, NULL},
+ {CFI_MFR_FUJITSU, 0x22ea, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_555_2AA]},
{CFI_MFR_FUJITSU, 0x226b, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_5555_2AAA]},
{CFI_MFR_AMIC, 0xb31a, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_555_2AA]},
{CFI_MFR_MX, 0x225b, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_555_2AA]},
}
return bank->base + bank->sectors[sector].offset + offset * bank->bus_width;
}
-
}
static void cfi_command(struct flash_bank *bank, uint8_t cmd, uint8_t *cmd_buf)
data[(3 * bank->bus_width) - 1] << 16 | data[(4 * bank->bus_width) - 1] << 24;
}
+static int cfi_reset(struct flash_bank *bank)
+{
+ struct cfi_flash_bank *cfi_info = bank->driver_priv;
+ int retval = ERROR_OK;
+
+ if ((retval = cfi_send_command(bank, 0xf0, flash_address(bank, 0, 0x0))) != ERROR_OK)
+ {
+ return retval;
+ }
+
+ if ((retval = cfi_send_command(bank, 0xff, flash_address(bank, 0, 0x0))) != ERROR_OK)
+ {
+ return retval;
+ }
+
+ if (cfi_info->manufacturer == 0x20 &&
+ (cfi_info->device_id == 0x227E || cfi_info->device_id == 0x7E))
+ {
+ /* Numonix M29W128G is cmd 0xFF intolerant - causes internal undefined state
+ * so we send an extra 0xF0 reset to fix the bug */
+ if ((retval = cfi_send_command(bank, 0xf0, flash_address(bank, 0, 0x00))) != ERROR_OK)
+ {
+ return retval;
+ }
+ }
+
+ return retval;
+}
+
static void cfi_intel_clear_status_register(struct flash_bank *bank)
{
struct target *target = bank->target;
cfi_send_command(bank, 0x50, flash_address(bank, 0, 0x0));
}
-uint8_t cfi_intel_wait_status_busy(struct flash_bank *bank, int timeout)
+static uint8_t cfi_intel_wait_status_busy(struct flash_bank *bank, int timeout)
{
uint8_t status;
return status;
}
-int cfi_spansion_wait_status_busy(struct flash_bank *bank, int timeout)
+static int cfi_spansion_wait_status_busy(struct flash_bank *bank, int timeout)
{
uint8_t status, oldstatus;
struct cfi_flash_bank *cfi_info = bank->driver_priv;
if ((pri_ext->pri[0] != 'P') || (pri_ext->pri[1] != 'R') || (pri_ext->pri[2] != 'I'))
{
- if ((retval = cfi_send_command(bank, 0xf0, flash_address(bank, 0, 0x0))) != ERROR_OK)
- {
- return retval;
- }
- if ((retval = cfi_send_command(bank, 0xff, flash_address(bank, 0, 0x0))) != ERROR_OK)
+ if ((retval = cfi_reset(bank)) != ERROR_OK)
{
return retval;
}
return ERROR_FLASH_BANK_INVALID;
}
- uint16_t chip_width, bus_width;
- COMMAND_PARSE_NUMBER(u16, CMD_ARGV[3], bus_width);
- COMMAND_PARSE_NUMBER(u16, CMD_ARGV[4], chip_width);
-
- if ((chip_width > CFI_MAX_CHIP_WIDTH)
- || (bus_width > CFI_MAX_BUS_WIDTH))
+ /* both widths must:
+ * - not exceed max value;
+ * - not be null;
+ * - be equal to a power of 2.
+ * bus must be wide enought to hold one chip */
+ if ((bank->chip_width > CFI_MAX_CHIP_WIDTH)
+ || (bank->bus_width > CFI_MAX_BUS_WIDTH)
+ || (bank->chip_width == 0)
+ || (bank->bus_width == 0)
+ || (bank->chip_width & (bank->chip_width - 1))
+ || (bank->bus_width & (bank->bus_width - 1))
+ || (bank->chip_width > bank->bus_width))
{
LOG_ERROR("chip and bus width have to specified in bytes");
return ERROR_FLASH_BANK_INVALID;
*/
if ((!set) && (!(pri_ext->feature_support & 0x20)))
{
+ /* FIX!!! this code path is broken!!!
+ *
+ * The correct approach is:
+ *
+ * 1. read out current protection status
+ *
+ * 2. override read out protection status w/unprotected.
+ *
+ * 3. re-protect what should be protected.
+ *
+ */
for (i = 0; i < bank->num_sectors; i++)
{
if (bank->sectors[i].is_protected == 1)
if ((first < 0) || (last < first) || (last >= bank->num_sectors))
{
+ LOG_ERROR("Invalid sector range");
return ERROR_FLASH_SECTOR_INVALID;
}
{
case 1:
case 3:
- cfi_intel_protect(bank, set, first, last);
+ return cfi_intel_protect(bank, set, first, last);
break;
default:
LOG_ERROR("protect: cfi primary command set %i unsupported", cfi_info->pri_id);
- break;
+ return ERROR_FAIL;
}
-
- return ERROR_OK;
}
/* FIXME Replace this by a simple memcpy() - still unsure about sideeffects */
/* Get a workspace buffer for the data to flash starting with 32k size.
Half size until buffer would be smaller 256 Bytem then fail back */
/* FIXME Why 256 bytes, why not 32 bytes (smallest flash write page */
- while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK)
+ while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK)
{
buffer_size /= 2;
if (buffer_size <= 256)
busy_pattern_val = cfi_command_val(bank, 0x80);
error_pattern_val = cfi_command_val(bank, 0x7e);
- LOG_INFO("Using target buffer at 0x%08" PRIx32 " and of size 0x%04" PRIx32, source->address, buffer_size);
+ LOG_DEBUG("Using target buffer at 0x%08" PRIx32 " and of size 0x%04" PRIx32, source->address, buffer_size);
/* Programming main loop */
while (count > 0)
buf_set_u32(reg_params[5].value, 0, 32, busy_pattern_val);
buf_set_u32(reg_params[6].value, 0, 32, error_pattern_val);
- LOG_INFO("Write 0x%04" PRIx32 " bytes to flash at 0x%08" PRIx32 , thisrun_count, address);
+ LOG_DEBUG("Write 0x%04" PRIx32 " bytes to flash at 0x%08" PRIx32 , thisrun_count, address);
/* Execute algorithm, assume breakpoint for last instruction */
retval = target_run_algorithm(target, 0, NULL, 7, reg_params,
}
/* the following code still assumes target code is fixed 24*4 bytes */
- while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK)
+ while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK)
{
buffer_size /= 2;
if (buffer_size <= 256)
struct target *target = bank->target;
/* Calculate buffer size and boundary mask */
+ /* buffersize is (buffer size per chip) * (number of chips) */
+ /* bufferwsize is buffersize in words */
uint32_t buffersize = (1UL << cfi_info->max_buf_write_size) * (bank->bus_width / bank->chip_width);
uint32_t buffermask = buffersize-1;
- uint32_t bufferwsize;
+ uint32_t bufferwsize = buffersize / bank->bus_width;
/* Check for valid range */
if (address & buffermask)
bank->base, address, cfi_info->max_buf_write_size);
return ERROR_FLASH_OPERATION_FAILED;
}
- switch (bank->chip_width)
- {
- case 4 : bufferwsize = buffersize / 4; break;
- case 2 : bufferwsize = buffersize / 2; break;
- case 1 : bufferwsize = buffersize; break;
- default:
- LOG_ERROR("Unsupported chip width %d", bank->chip_width);
- return ERROR_FLASH_OPERATION_FAILED;
- }
-
- bufferwsize/=(bank->bus_width / bank->chip_width);
-
/* Check for valid size */
if (wordcount > bufferwsize)
struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext;
/* Calculate buffer size and boundary mask */
+ /* buffersize is (buffer size per chip) * (number of chips) */
+ /* bufferwsize is buffersize in words */
uint32_t buffersize = (1UL << cfi_info->max_buf_write_size) * (bank->bus_width / bank->chip_width);
uint32_t buffermask = buffersize-1;
- uint32_t bufferwsize;
+ uint32_t bufferwsize = buffersize / bank->bus_width;
/* Check for valid range */
if (address & buffermask)
LOG_ERROR("Write address at base 0x%" PRIx32 ", address %" PRIx32 " not aligned to 2^%d boundary", bank->base, address, cfi_info->max_buf_write_size);
return ERROR_FLASH_OPERATION_FAILED;
}
- switch (bank->chip_width)
- {
- case 4 : bufferwsize = buffersize / 4; break;
- case 2 : bufferwsize = buffersize / 2; break;
- case 1 : bufferwsize = buffersize; break;
- default:
- LOG_ERROR("Unsupported chip width %d", bank->chip_width);
- return ERROR_FLASH_OPERATION_FAILED;
- }
-
- bufferwsize/=(bank->bus_width / bank->chip_width);
/* Check for valid size */
if (wordcount > bufferwsize)
return ERROR_FLASH_OPERATION_FAILED;
}
-int cfi_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
+static int cfi_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
{
struct cfi_flash_bank *cfi_info = bank->driver_priv;
struct target *target = bank->target;
for (i = 0; i < align; ++i, ++copy_p)
{
uint8_t byte;
+ /* FIXME: access flash at bus_width size */
if ((retval = target_read_memory(target, copy_p, 1, 1, &byte)) != ERROR_OK)
{
return retval;
for (; (count == 0) && (i < bank->bus_width); ++i, ++copy_p)
{
uint8_t byte;
+ /* FIXME: access flash at bus_width size */
if ((retval = target_read_memory(target, copy_p, 1, 1, &byte)) != ERROR_OK)
{
return retval;
{
if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
{
- //adjust buffersize for chip width
+ /* Calculate buffer size and boundary mask */
+ /* buffersize is (buffer size per chip) * (number of chips) */
+ /* bufferwsize is buffersize in words */
uint32_t buffersize = (1UL << cfi_info->max_buf_write_size) * (bank->bus_width / bank->chip_width);
uint32_t buffermask = buffersize-1;
- uint32_t bufferwsize;
-
- switch (bank->chip_width)
- {
- case 4 : bufferwsize = buffersize / 4; break;
- case 2 : bufferwsize = buffersize / 2; break;
- case 1 : bufferwsize = buffersize; break;
- default:
- LOG_ERROR("Unsupported chip width %d", bank->chip_width);
- return ERROR_FLASH_OPERATION_FAILED;
- }
-
- bufferwsize/=(bank->bus_width / bank->chip_width);
+ uint32_t bufferwsize = buffersize / bank->bus_width;
/* fall back to memory writes */
while (count >= (uint32_t)bank->bus_width)
}
/* return to read array mode, so we can read from flash again for padding */
- if ((retval = cfi_send_command(bank, 0xf0, flash_address(bank, 0, 0x0))) != ERROR_OK)
- {
- return retval;
- }
- if ((retval = cfi_send_command(bank, 0xff, flash_address(bank, 0, 0x0))) != ERROR_OK)
+ if ((retval = cfi_reset(bank)) != ERROR_OK)
{
return retval;
}
for (; i < bank->bus_width; ++i, ++copy_p)
{
uint8_t byte;
+ /* FIXME: access flash at bus_width size */
if ((retval = target_read_memory(target, copy_p, 1, 1, &byte)) != ERROR_OK)
{
return retval;
}
/* return to read array mode */
- if ((retval = cfi_send_command(bank, 0xf0, flash_address(bank, 0, 0x0))) != ERROR_OK)
- {
- return retval;
- }
- return cfi_send_command(bank, 0xff, flash_address(bank, 0, 0x0));
+ return cfi_reset(bank);
}
static void cfi_fixup_atmel_reversed_erase_regions(struct flash_bank *bank, void *param)
if ((cfi_info->qry[0] != 'Q') || (cfi_info->qry[1] != 'R') || (cfi_info->qry[2] != 'Y'))
{
- if ((retval = cfi_send_command(bank, 0xf0, flash_address(bank, 0, 0x0))) != ERROR_OK)
- {
- return retval;
- }
- if ((retval = cfi_send_command(bank, 0xff, flash_address(bank, 0, 0x0))) != ERROR_OK)
+ if ((retval = cfi_reset(bank)) != ERROR_OK)
{
return retval;
}
if (bank->chip_width == 1)
{
uint8_t manufacturer, device_id;
+ /* FIXME: access flash at bus_width size */
if ((retval = target_read_u8(target, flash_address(bank, 0, 0x00), &manufacturer)) != ERROR_OK)
{
return retval;
}
+ /* FIXME: access flash at bus_width size */
if ((retval = target_read_u8(target, flash_address(bank, 0, 0x01), &device_id)) != ERROR_OK)
{
return retval;
}
else if (bank->chip_width == 2)
{
+ /* FIXME: access flash at bus_width size */
if ((retval = target_read_u16(target, flash_address(bank, 0, 0x00), &cfi_info->manufacturer)) != ERROR_OK)
{
return retval;
}
+ /* FIXME: access flash at bus_width size */
if ((retval = target_read_u16(target, flash_address(bank, 0, 0x01), &cfi_info->device_id)) != ERROR_OK)
{
return retval;
LOG_INFO("Flash Manufacturer/Device: 0x%04x 0x%04x", cfi_info->manufacturer, cfi_info->device_id);
/* switch back to read array mode */
- if ((retval = cfi_send_command(bank, 0xf0, flash_address(bank, 0, 0x00))) != ERROR_OK)
- {
- return retval;
- }
- if ((retval = cfi_send_command(bank, 0xff, flash_address(bank, 0, 0x00))) != ERROR_OK)
+ if ((retval = cfi_reset(bank)) != ERROR_OK)
{
return retval;
}
/* return to read array mode
* we use both reset commands, as some Intel flashes fail to recognize the 0xF0 command
*/
- if ((retval = cfi_send_command(bank, 0xf0, flash_address(bank, 0, 0x0))) != ERROR_OK)
- {
- return retval;
- }
- if ((retval = cfi_send_command(bank, 0xff, flash_address(bank, 0, 0x0))) != ERROR_OK)
+ if ((retval = cfi_reset(bank)) != ERROR_OK)
{
return retval;
}
return cfi_probe(bank);
}
-
static int cfi_intel_protect_check(struct flash_bank *bank)
{
int retval;
.write = cfi_write,
.probe = cfi_probe,
.auto_probe = cfi_auto_probe,
+ /* FIXME: access flash at bus_width size */
.erase_check = default_flash_blank_check,
.protect_check = cfi_protect_check,
.info = cfi_info,