From 32b67ee3c9ec10f6ef04ff3deb327a40665ed8b3 Mon Sep 17 00:00:00 2001 From: Esben Haabendal Date: Fri, 23 Oct 2015 10:12:59 +0200 Subject: [PATCH] cfi: support for 16-bit flash with reversed endianness This is for targets where flash controller has reverse endianness compared to target. For these, the 'bus_swap' parameter can be given to the CFI driver, which will cause command CFI commands to be written with bytes swapped. This is only for x16 CFI flash. Change-Id: I698b768e92e65d160232e90b0e81a824e3c81a46 Signed-off-by: Esben Haabendal Reviewed-on: http://openocd.zylin.com/3041 Tested-by: jenkins Reviewed-by: Spencer Oliver --- doc/openocd.texi | 1 + src/flash/nor/cfi.c | 23 ++++++++++++++++++----- src/flash/nor/cfi.h | 2 ++ 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/doc/openocd.texi b/doc/openocd.texi index 2e451140..acda084d 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -4806,6 +4806,7 @@ The CFI driver can accept the following optional parameters, in any order: @item @var{jedec_probe} ... is used to detect certain non-CFI flash ROMs, like AM29LV010 and similar types. @item @var{x16_as_x8} ... when a 16-bit flash is hooked up to an 8-bit bus. +@item @var{bus_swap} ... when data bytes in a 16-bit flash needs to be swapped. @end itemize To configure two adjacent banks of 16 MBytes each, both sixteen bits (two bytes) diff --git a/src/flash/nor/cfi.c b/src/flash/nor/cfi.c index efa0aeec..b8088300 100644 --- a/src/flash/nor/cfi.c +++ b/src/flash/nor/cfi.c @@ -136,6 +136,7 @@ static inline uint32_t flash_address(struct flash_bank *bank, int sector, uint32 static void cfi_command(struct flash_bank *bank, uint8_t cmd, uint8_t *cmd_buf) { int i; + struct cfi_flash_bank *cfi_info = bank->driver_priv; /* clear whole buffer, to ensure bits that exceed the bus_width * are set to zero @@ -143,7 +144,7 @@ static void cfi_command(struct flash_bank *bank, uint8_t cmd, uint8_t *cmd_buf) for (i = 0; i < CFI_MAX_BUS_WIDTH; i++) cmd_buf[i] = 0; - if (bank->target->endianness == TARGET_LITTLE_ENDIAN) { + if (cfi_info->endianness == TARGET_LITTLE_ENDIAN) { for (i = bank->bus_width; i > 0; i--) *cmd_buf++ = (i & (bank->chip_width - 1)) ? 0x0 : cmd; } else { @@ -167,6 +168,7 @@ static int cfi_send_command(struct flash_bank *bank, uint8_t cmd, uint32_t addre static int cfi_query_u8(struct flash_bank *bank, int sector, uint32_t offset, uint8_t *val) { struct target *target = bank->target; + struct cfi_flash_bank *cfi_info = bank->driver_priv; uint8_t data[CFI_MAX_BUS_WIDTH]; int retval; @@ -175,7 +177,7 @@ static int cfi_query_u8(struct flash_bank *bank, int sector, uint32_t offset, ui if (retval != ERROR_OK) return retval; - if (bank->target->endianness == TARGET_LITTLE_ENDIAN) + if (cfi_info->endianness == TARGET_LITTLE_ENDIAN) *val = data[0]; else *val = data[bank->bus_width - 1]; @@ -190,6 +192,7 @@ static int cfi_query_u8(struct flash_bank *bank, int sector, uint32_t offset, ui static int cfi_get_u8(struct flash_bank *bank, int sector, uint32_t offset, uint8_t *val) { struct target *target = bank->target; + struct cfi_flash_bank *cfi_info = bank->driver_priv; uint8_t data[CFI_MAX_BUS_WIDTH]; int i; @@ -199,7 +202,7 @@ static int cfi_get_u8(struct flash_bank *bank, int sector, uint32_t offset, uint if (retval != ERROR_OK) return retval; - if (bank->target->endianness == TARGET_LITTLE_ENDIAN) { + if (cfi_info->endianness == TARGET_LITTLE_ENDIAN) { for (i = 0; i < bank->bus_width / bank->chip_width; i++) data[0] |= data[i]; @@ -236,7 +239,7 @@ static int cfi_query_u16(struct flash_bank *bank, int sector, uint32_t offset, u return retval; } - if (bank->target->endianness == TARGET_LITTLE_ENDIAN) + if (cfi_info->endianness == TARGET_LITTLE_ENDIAN) *val = data[0] | data[bank->bus_width] << 8; else *val = data[bank->bus_width - 1] | data[(2 * bank->bus_width) - 1] << 8; @@ -266,7 +269,7 @@ static int cfi_query_u32(struct flash_bank *bank, int sector, uint32_t offset, u return retval; } - if (bank->target->endianness == TARGET_LITTLE_ENDIAN) + if (cfi_info->endianness == TARGET_LITTLE_ENDIAN) *val = data[0] | data[bank->bus_width] << 8 | data[bank->bus_width * 2] << 16 | data[bank->bus_width * 3] << 24; else @@ -803,6 +806,7 @@ static int cfi_intel_info(struct flash_bank *bank, char *buf, int buf_size) FLASH_BANK_COMMAND_HANDLER(cfi_flash_bank_command) { struct cfi_flash_bank *cfi_info; + int bus_swap = 0; if (CMD_ARGC < 6) return ERROR_COMMAND_SYNTAX_ERROR; @@ -836,10 +840,19 @@ FLASH_BANK_COMMAND_HANDLER(cfi_flash_bank_command) for (unsigned i = 6; i < CMD_ARGC; i++) { if (strcmp(CMD_ARGV[i], "x16_as_x8") == 0) cfi_info->x16_as_x8 = 1; + else if (strcmp(CMD_ARGV[i], "bus_swap") == 0) + bus_swap = 1; else if (strcmp(CMD_ARGV[i], "jedec_probe") == 0) cfi_info->jedec_probe = 1; } + if (bus_swap) + cfi_info->endianness = + bank->target->endianness == TARGET_LITTLE_ENDIAN ? + TARGET_BIG_ENDIAN : TARGET_LITTLE_ENDIAN; + else + cfi_info->endianness = bank->target->endianness; + /* bank wasn't probed yet */ cfi_info->qry[0] = 0xff; diff --git a/src/flash/nor/cfi.h b/src/flash/nor/cfi.h index d92fcc0b..5bd25e97 100644 --- a/src/flash/nor/cfi.h +++ b/src/flash/nor/cfi.h @@ -30,6 +30,8 @@ struct cfi_flash_bank { int not_cfi; int probed; + enum target_endianness endianness; + uint16_t manufacturer; uint16_t device_id; -- 2.39.5