Change-Id: I21bb466a35168cf04743f5baafac9fef50d01707 Signed-off-by: Spencer Oliver <spen@spen-soft.co.uk> Reviewed-on: http://openocd.zylin.com/419 Tested-by: jenkinstags/v0.6.0-rc1
@@ -30,7 +30,6 @@ | |||
#include <target/arm.h> | |||
#include <target/algorithm.h> | |||
/** | |||
* Copies code to a working area. This will allocate room for the code plus the | |||
* additional amount requested if the working area pointer is null. | |||
@@ -44,8 +43,8 @@ | |||
* @return Success or failure of the operation | |||
*/ | |||
static int arm_code_to_working_area(struct target *target, | |||
const uint32_t *code, unsigned code_size, | |||
unsigned additional, struct working_area **area) | |||
const uint32_t *code, unsigned code_size, | |||
unsigned additional, struct working_area **area) | |||
{ | |||
uint8_t code_buf[code_size]; | |||
unsigned i; | |||
@@ -61,7 +60,7 @@ static int arm_code_to_working_area(struct target *target, | |||
if (NULL == *area) { | |||
retval = target_alloc_working_area(target, size, area); | |||
if (retval != ERROR_OK) { | |||
LOG_DEBUG("%s: no %d byte buffer", __FUNCTION__, (int) size); | |||
LOG_DEBUG("%s: no %d byte buffer", __func__, (int) size); | |||
return ERROR_NAND_NO_BUFFER; | |||
} | |||
} | |||
@@ -95,13 +94,13 @@ static int arm_code_to_working_area(struct target *target, | |||
*/ | |||
int arm_nandwrite(struct arm_nand_data *nand, uint8_t *data, int size) | |||
{ | |||
struct target *target = nand->target; | |||
struct arm_algorithm algo; | |||
struct arm *arm = target->arch_info; | |||
struct reg_param reg_params[3]; | |||
uint32_t target_buf; | |||
uint32_t exit_var = 0; | |||
int retval; | |||
struct target *target = nand->target; | |||
struct arm_algorithm algo; | |||
struct arm *arm = target->arch_info; | |||
struct reg_param reg_params[3]; | |||
uint32_t target_buf; | |||
uint32_t exit_var = 0; | |||
int retval; | |||
/* Inputs: | |||
* r0 NAND data address (byte wide) | |||
@@ -121,9 +120,8 @@ int arm_nandwrite(struct arm_nand_data *nand, uint8_t *data, int size) | |||
if (nand->op != ARM_NAND_WRITE || !nand->copy_area) { | |||
retval = arm_code_to_working_area(target, code, sizeof(code), | |||
nand->chunk_size, &nand->copy_area); | |||
if (retval != ERROR_OK) { | |||
if (retval != ERROR_OK) | |||
return retval; | |||
} | |||
} | |||
nand->op = ARM_NAND_WRITE; | |||
@@ -206,9 +204,8 @@ int arm_nandread(struct arm_nand_data *nand, uint8_t *data, uint32_t size) | |||
if (nand->op != ARM_NAND_READ || !nand->copy_area) { | |||
retval = arm_code_to_working_area(target, code, sizeof(code), | |||
nand->chunk_size, &nand->copy_area); | |||
if (retval != ERROR_OK) { | |||
if (retval != ERROR_OK) | |||
return retval; | |||
} | |||
} | |||
nand->op = ARM_NAND_READ; | |||
@@ -246,4 +243,3 @@ int arm_nandread(struct arm_nand_data *nand, uint8_t *data, uint32_t size) | |||
return retval; | |||
} | |||
@@ -23,9 +23,9 @@ | |||
* Available operational states the arm_nand_data struct can be in. | |||
*/ | |||
enum arm_nand_op { | |||
ARM_NAND_NONE, /**< No operation performed. */ | |||
ARM_NAND_READ, /**< Read operation performed. */ | |||
ARM_NAND_WRITE, /**< Write operation performed. */ | |||
ARM_NAND_NONE, /**< No operation performed. */ | |||
ARM_NAND_READ, /**< Read operation performed. */ | |||
ARM_NAND_WRITE, /**< Write operation performed. */ | |||
}; | |||
/** | |||
@@ -37,7 +37,7 @@ struct arm_nand_data { | |||
struct target *target; | |||
/** The copy area holds code loop and data for I/O operations. */ | |||
struct working_area *copy_area; | |||
struct working_area *copy_area; | |||
/** The chunk size is the page size or ECC chunk. */ | |||
unsigned chunk_size; | |||
@@ -54,4 +54,4 @@ struct arm_nand_data { | |||
int arm_nandwrite(struct arm_nand_data *nand, uint8_t *data, int size); | |||
int arm_nandread(struct arm_nand_data *nand, uint8_t *data, uint32_t size); | |||
#endif /* __ARM_NANDIO_H */ | |||
#endif /* __ARM_NANDIO_H */ |
@@ -17,6 +17,7 @@ | |||
* Free Software Foundation, Inc., | |||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
*/ | |||
#ifdef HAVE_CONFIG_H | |||
#include "config.h" | |||
#endif | |||
@@ -26,13 +27,13 @@ | |||
#include "imp.h" | |||
#include "arm_io.h" | |||
#define AT91C_PIOx_SODR (0x30) /**< Offset to PIO SODR. */ | |||
#define AT91C_PIOx_CODR (0x34) /**< Offset to PIO CODR. */ | |||
#define AT91C_PIOx_PDSR (0x3C) /**< Offset to PIO PDSR. */ | |||
#define AT91C_ECCx_CR (0x00) /**< Offset to ECC CR. */ | |||
#define AT91C_ECCx_SR (0x08) /**< Offset to ECC SR. */ | |||
#define AT91C_ECCx_PR (0x0C) /**< Offset to ECC PR. */ | |||
#define AT91C_ECCx_NPR (0x10) /**< Offset to ECC NPR. */ | |||
#define AT91C_PIOx_SODR (0x30) /**< Offset to PIO SODR. */ | |||
#define AT91C_PIOx_CODR (0x34) /**< Offset to PIO CODR. */ | |||
#define AT91C_PIOx_PDSR (0x3C) /**< Offset to PIO PDSR. */ | |||
#define AT91C_ECCx_CR (0x00) /**< Offset to ECC CR. */ | |||
#define AT91C_ECCx_SR (0x08) /**< Offset to ECC SR. */ | |||
#define AT91C_ECCx_PR (0x0C) /**< Offset to ECC PR. */ | |||
#define AT91C_ECCx_NPR (0x10) /**< Offset to ECC NPR. */ | |||
/** | |||
* Representation of a pin on an AT91SAM9 chip. | |||
@@ -97,9 +98,8 @@ static int at91sam9_init(struct nand_device *nand) | |||
{ | |||
struct target *target = nand->target; | |||
if (!at91sam9_halted(target, "init")) { | |||
if (!at91sam9_halted(target, "init")) | |||
return ERROR_NAND_OPERATION_FAILED; | |||
} | |||
return ERROR_OK; | |||
} | |||
@@ -144,9 +144,8 @@ static int at91sam9_command(struct nand_device *nand, uint8_t command) | |||
struct at91sam9_nand *info = nand->controller_priv; | |||
struct target *target = nand->target; | |||
if (!at91sam9_halted(target, "command")) { | |||
if (!at91sam9_halted(target, "command")) | |||
return ERROR_NAND_OPERATION_FAILED; | |||
} | |||
at91sam9_enable(nand); | |||
@@ -161,9 +160,8 @@ static int at91sam9_command(struct nand_device *nand, uint8_t command) | |||
*/ | |||
static int at91sam9_reset(struct nand_device *nand) | |||
{ | |||
if (!at91sam9_halted(nand->target, "reset")) { | |||
if (!at91sam9_halted(nand->target, "reset")) | |||
return ERROR_NAND_OPERATION_FAILED; | |||
} | |||
return at91sam9_disable(nand); | |||
} | |||
@@ -180,9 +178,8 @@ static int at91sam9_address(struct nand_device *nand, uint8_t address) | |||
struct at91sam9_nand *info = nand->controller_priv; | |||
struct target *target = nand->target; | |||
if (!at91sam9_halted(nand->target, "address")) { | |||
if (!at91sam9_halted(nand->target, "address")) | |||
return ERROR_NAND_OPERATION_FAILED; | |||
} | |||
return target_write_u8(target, info->addr, address); | |||
} | |||
@@ -200,9 +197,8 @@ static int at91sam9_read_data(struct nand_device *nand, void *data) | |||
struct at91sam9_nand *info = nand->controller_priv; | |||
struct target *target = nand->target; | |||
if (!at91sam9_halted(nand->target, "read data")) { | |||
if (!at91sam9_halted(nand->target, "read data")) | |||
return ERROR_NAND_OPERATION_FAILED; | |||
} | |||
return target_read_u8(target, info->data, data); | |||
} | |||
@@ -220,9 +216,8 @@ static int at91sam9_write_data(struct nand_device *nand, uint16_t data) | |||
struct at91sam9_nand *info = nand->controller_priv; | |||
struct target *target = nand->target; | |||
if (!at91sam9_halted(target, "write data")) { | |||
if (!at91sam9_halted(target, "write data")) | |||
return ERROR_NAND_OPERATION_FAILED; | |||
} | |||
return target_write_u8(target, info->data, data); | |||
} | |||
@@ -240,16 +235,14 @@ static int at91sam9_nand_ready(struct nand_device *nand, int timeout) | |||
struct target *target = nand->target; | |||
uint32_t status; | |||
if (!at91sam9_halted(target, "nand ready")) { | |||
if (!at91sam9_halted(target, "nand ready")) | |||
return 0; | |||
} | |||
do { | |||
target_read_u32(target, info->busy.pioc + AT91C_PIOx_PDSR, &status); | |||
if (status & (1 << info->busy.num)) { | |||
if (status & (1 << info->busy.num)) | |||
return 1; | |||
} | |||
alive_sleep(1); | |||
} while (timeout-- > 0); | |||
@@ -272,9 +265,8 @@ static int at91sam9_read_block_data(struct nand_device *nand, uint8_t *data, int | |||
struct arm_nand_data *io = &info->io; | |||
int status; | |||
if (!at91sam9_halted(nand->target, "read block")) { | |||
if (!at91sam9_halted(nand->target, "read block")) | |||
return ERROR_NAND_OPERATION_FAILED; | |||
} | |||
io->chunk_size = nand->page_size; | |||
status = arm_nandread(io, data, size); | |||
@@ -297,9 +289,8 @@ static int at91sam9_write_block_data(struct nand_device *nand, uint8_t *data, in | |||
struct arm_nand_data *io = &info->io; | |||
int status; | |||
if (!at91sam9_halted(nand->target, "write block")) { | |||
if (!at91sam9_halted(nand->target, "write block")) | |||
return ERROR_NAND_OPERATION_FAILED; | |||
} | |||
io->chunk_size = nand->page_size; | |||
status = arm_nandwrite(io, data, size); | |||
@@ -321,7 +312,7 @@ static int at91sam9_ecc_init(struct target *target, struct at91sam9_nand *info) | |||
return ERROR_NAND_OPERATION_FAILED; | |||
} | |||
// reset ECC parity registers | |||
/* reset ECC parity registers */ | |||
return target_write_u32(target, info->ecc + AT91C_ECCx_CR, 1); | |||
} | |||
@@ -335,15 +326,14 @@ static int at91sam9_ecc_init(struct target *target, struct at91sam9_nand *info) | |||
* @param size Size of the OOB. | |||
* @return Pointer to an area to store OOB data. | |||
*/ | |||
static uint8_t * at91sam9_oob_init(struct nand_device *nand, uint8_t *oob, uint32_t *size) | |||
static uint8_t *at91sam9_oob_init(struct nand_device *nand, uint8_t *oob, uint32_t *size) | |||
{ | |||
if (!oob) { | |||
// user doesn't want OOB, allocate it | |||
if (nand->page_size == 512) { | |||
/* user doesn't want OOB, allocate it */ | |||
if (nand->page_size == 512) | |||
*size = 16; | |||
} else if (nand->page_size == 2048) { | |||
else if (nand->page_size == 2048) | |||
*size = 64; | |||
} | |||
oob = malloc(*size); | |||
if (!oob) { | |||
@@ -371,7 +361,7 @@ static uint8_t * at91sam9_oob_init(struct nand_device *nand, uint8_t *oob, uint3 | |||
* @return Success or failure of reading the NAND page. | |||
*/ | |||
static int at91sam9_read_page(struct nand_device *nand, uint32_t page, | |||
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) | |||
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) | |||
{ | |||
int retval; | |||
struct at91sam9_nand *info = nand->controller_priv; | |||
@@ -380,20 +370,17 @@ static int at91sam9_read_page(struct nand_device *nand, uint32_t page, | |||
uint32_t status; | |||
retval = at91sam9_ecc_init(target, info); | |||
if (ERROR_OK != retval) { | |||
if (ERROR_OK != retval) | |||
return retval; | |||
} | |||
retval = nand_page_command(nand, page, NAND_CMD_READ0, !data); | |||
if (ERROR_OK != retval) { | |||
if (ERROR_OK != retval) | |||
return retval; | |||
} | |||
if (data) { | |||
retval = nand_read_data_page(nand, data, data_size); | |||
if (ERROR_OK != retval) { | |||
if (ERROR_OK != retval) | |||
return retval; | |||
} | |||
} | |||
oob_data = at91sam9_oob_init(nand, oob, &oob_size); | |||
@@ -402,33 +389,33 @@ static int at91sam9_read_page(struct nand_device *nand, uint32_t page, | |||
target_read_u32(target, info->ecc + AT91C_ECCx_SR, &status); | |||
if (status & 1) { | |||
LOG_ERROR("Error detected!"); | |||
if (status & 4) { | |||
if (status & 4) | |||
LOG_ERROR("Multiple errors encountered; unrecoverable!"); | |||
} else { | |||
// attempt recovery | |||
else { | |||
/* attempt recovery */ | |||
uint32_t parity; | |||
target_read_u32(target, | |||
info->ecc + AT91C_ECCx_PR, | |||
&parity); | |||
info->ecc + AT91C_ECCx_PR, | |||
&parity); | |||
uint32_t word = (parity & 0x0000FFF0) >> 4; | |||
uint32_t bit = parity & 0x0F; | |||
data[word] ^= (0x1) << bit; | |||
LOG_INFO("Data word %d, bit %d corrected.", | |||
(unsigned) word, | |||
(unsigned) bit); | |||
(unsigned) word, | |||
(unsigned) bit); | |||
} | |||
} | |||
if (status & 2) { | |||
// we could write back correct ECC data | |||
/* we could write back correct ECC data */ | |||
LOG_ERROR("Error in ECC bytes detected"); | |||
} | |||
} | |||
if (!oob) { | |||
// if it wasn't asked for, free it | |||
/* if it wasn't asked for, free it */ | |||
free(oob_data); | |||
} | |||
@@ -449,7 +436,7 @@ static int at91sam9_read_page(struct nand_device *nand, uint32_t page, | |||
* @return Success or failure of the page write. | |||
*/ | |||
static int at91sam9_write_page(struct nand_device *nand, uint32_t page, | |||
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) | |||
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) | |||
{ | |||
struct at91sam9_nand *info = nand->controller_priv; | |||
struct target *target = nand->target; | |||
@@ -458,14 +445,12 @@ static int at91sam9_write_page(struct nand_device *nand, uint32_t page, | |||
uint32_t parity, nparity; | |||
retval = at91sam9_ecc_init(target, info); | |||
if (ERROR_OK != retval) { | |||
if (ERROR_OK != retval) | |||
return retval; | |||
} | |||
retval = nand_page_command(nand, page, NAND_CMD_SEQIN, !data); | |||
if (ERROR_OK != retval) { | |||
if (ERROR_OK != retval) | |||
return retval; | |||
} | |||
if (data) { | |||
retval = nand_write_data_page(nand, data, data_size); | |||
@@ -478,7 +463,7 @@ static int at91sam9_write_page(struct nand_device *nand, uint32_t page, | |||
oob_data = at91sam9_oob_init(nand, oob, &oob_size); | |||
if (!oob) { | |||
// no OOB given, so read in the ECC parity from the ECC controller | |||
/* no OOB given, so read in the ECC parity from the ECC controller */ | |||
target_read_u32(target, info->ecc + AT91C_ECCx_PR, &parity); | |||
target_read_u32(target, info->ecc + AT91C_ECCx_NPR, &nparity); | |||
@@ -490,9 +475,8 @@ static int at91sam9_write_page(struct nand_device *nand, uint32_t page, | |||
retval = nand_write_data_page(nand, oob_data, oob_size); | |||
if (!oob) { | |||
if (!oob) | |||
free(oob_data); | |||
} | |||
if (ERROR_OK != retval) { | |||
LOG_ERROR("Unable to write OOB data to NAND"); | |||
@@ -594,9 +578,8 @@ COMMAND_HANDLER(handle_at91sam9_ale_command) | |||
struct at91sam9_nand *info = NULL; | |||
unsigned num, address_line; | |||
if (CMD_ARGC != 2) { | |||
if (CMD_ARGC != 2) | |||
return ERROR_COMMAND_SYNTAX_ERROR; | |||
} | |||
COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], num); | |||
nand = get_nand_device_by_num(num); | |||
@@ -623,9 +606,8 @@ COMMAND_HANDLER(handle_at91sam9_rdy_busy_command) | |||
struct at91sam9_nand *info = NULL; | |||
unsigned num, base_pioc, pin_num; | |||
if (CMD_ARGC != 3) { | |||
if (CMD_ARGC != 3) | |||
return ERROR_COMMAND_SYNTAX_ERROR; | |||
} | |||
COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], num); | |||
nand = get_nand_device_by_num(num); | |||
@@ -655,9 +637,8 @@ COMMAND_HANDLER(handle_at91sam9_ce_command) | |||
struct at91sam9_nand *info = NULL; | |||
unsigned num, base_pioc, pin_num; | |||
if (CMD_ARGC != 3) { | |||
if (CMD_ARGC != 3) | |||
return ERROR_COMMAND_SYNTAX_ERROR; | |||
} | |||
COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], num); | |||
nand = get_nand_device_by_num(num); | |||
@@ -20,6 +20,7 @@ | |||
* Free Software Foundation, Inc., * | |||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * | |||
***************************************************************************/ | |||
#ifdef HAVE_CONFIG_H | |||
#include "config.h" | |||
#endif | |||
@@ -27,13 +28,14 @@ | |||
#include "imp.h" | |||
/* configured NAND devices and NAND Flash command handler */ | |||
struct nand_device *nand_devices = NULL; | |||
struct nand_device *nand_devices; | |||
void nand_device_add(struct nand_device *c) | |||
{ | |||
if (nand_devices) { | |||
struct nand_device *p = nand_devices; | |||
while (p && p->next) p = p->next; | |||
while (p && p->next) | |||
p = p->next; | |||
p->next = c; | |||
} else | |||
nand_devices = c; | |||
@@ -50,94 +52,94 @@ void nand_device_add(struct nand_device *c) | |||
* 256 256 Byte page size | |||
* 512 512 Byte page size | |||
*/ | |||
static struct nand_info nand_flash_ids[] = | |||
{ | |||
static struct nand_info nand_flash_ids[] = { | |||
/* Vendor Specific Entries */ | |||
{ NAND_MFR_SAMSUNG, 0xD5, 8192, 2048, 0x100000, LP_OPTIONS, "K9GAG08 2GB NAND 3.3V x8 MLC 2b/cell"}, | |||
{ NAND_MFR_SAMSUNG, 0xD7, 8192, 4096, 0x100000, LP_OPTIONS, "K9LBG08 4GB NAND 3.3V x8 MLC 2b/cell"}, | |||
{ NAND_MFR_SAMSUNG, 0xD5, 8192, 2048, 0x100000, LP_OPTIONS, | |||
"K9GAG08 2GB NAND 3.3V x8 MLC 2b/cell"}, | |||
{ NAND_MFR_SAMSUNG, 0xD7, 8192, 4096, 0x100000, LP_OPTIONS, | |||
"K9LBG08 4GB NAND 3.3V x8 MLC 2b/cell"}, | |||
/* start "museum" IDs */ | |||
{ 0x0, 0x6e, 256, 1, 0x1000, 0, "NAND 1MiB 5V 8-bit"}, | |||
{ 0x0, 0x64, 256, 2, 0x1000, 0, "NAND 2MiB 5V 8-bit"}, | |||
{ 0x0, 0x6b, 512, 4, 0x2000, 0, "NAND 4MiB 5V 8-bit"}, | |||
{ 0x0, 0xe8, 256, 1, 0x1000, 0, "NAND 1MiB 3.3V 8-bit"}, | |||
{ 0x0, 0xec, 256, 1, 0x1000, 0, "NAND 1MiB 3.3V 8-bit"}, | |||
{ 0x0, 0xea, 256, 2, 0x1000, 0, "NAND 2MiB 3.3V 8-bit"}, | |||
{ 0x0, 0xd5, 512, 4, 0x2000, 0, "NAND 4MiB 3.3V 8-bit"}, | |||
{ 0x0, 0xe3, 512, 4, 0x2000, 0, "NAND 4MiB 3.3V 8-bit"}, | |||
{ 0x0, 0xe5, 512, 4, 0x2000, 0, "NAND 4MiB 3.3V 8-bit"}, | |||
{ 0x0, 0xd6, 512, 8, 0x2000, 0, "NAND 8MiB 3.3V 8-bit"}, | |||
{ 0x0, 0x39, 512, 8, 0x2000, 0, "NAND 8MiB 1.8V 8-bit"}, | |||
{ 0x0, 0xe6, 512, 8, 0x2000, 0, "NAND 8MiB 3.3V 8-bit"}, | |||
{ 0x0, 0x49, 512, 8, 0x2000, NAND_BUSWIDTH_16, "NAND 8MiB 1.8V 16-bit"}, | |||
{ 0x0, 0x59, 512, 8, 0x2000, NAND_BUSWIDTH_16, "NAND 8MiB 3.3V 16-bit"}, | |||
{ 0x0, 0x6e, 256, 1, 0x1000, 0, "NAND 1MiB 5V 8-bit"}, | |||
{ 0x0, 0x64, 256, 2, 0x1000, 0, "NAND 2MiB 5V 8-bit"}, | |||
{ 0x0, 0x6b, 512, 4, 0x2000, 0, "NAND 4MiB 5V 8-bit"}, | |||
{ 0x0, 0xe8, 256, 1, 0x1000, 0, "NAND 1MiB 3.3V 8-bit"}, | |||
{ 0x0, 0xec, 256, 1, 0x1000, 0, "NAND 1MiB 3.3V 8-bit"}, | |||
{ 0x0, 0xea, 256, 2, 0x1000, 0, "NAND 2MiB 3.3V 8-bit"}, | |||
{ 0x0, 0xd5, 512, 4, 0x2000, 0, "NAND 4MiB 3.3V 8-bit"}, | |||
{ 0x0, 0xe3, 512, 4, 0x2000, 0, "NAND 4MiB 3.3V 8-bit"}, | |||
{ 0x0, 0xe5, 512, 4, 0x2000, 0, "NAND 4MiB 3.3V 8-bit"}, | |||
{ 0x0, 0xd6, 512, 8, 0x2000, 0, "NAND 8MiB 3.3V 8-bit"}, | |||
{ 0x0, 0x39, 512, 8, 0x2000, 0, "NAND 8MiB 1.8V 8-bit"}, | |||
{ 0x0, 0xe6, 512, 8, 0x2000, 0, "NAND 8MiB 3.3V 8-bit"}, | |||
{ 0x0, 0x49, 512, 8, 0x2000, NAND_BUSWIDTH_16, "NAND 8MiB 1.8V 16-bit"}, | |||
{ 0x0, 0x59, 512, 8, 0x2000, NAND_BUSWIDTH_16, "NAND 8MiB 3.3V 16-bit"}, | |||
/* end "museum" IDs */ | |||
{ 0x0, 0x33, 512, 16, 0x4000, 0, "NAND 16MiB 1.8V 8-bit"}, | |||
{ 0x0, 0x73, 512, 16, 0x4000, 0, "NAND 16MiB 3.3V 8-bit"}, | |||
{ 0x0, 0x43, 512, 16, 0x4000, NAND_BUSWIDTH_16,"NAND 16MiB 1.8V 16-bit"}, | |||
{ 0x0, 0x53, 512, 16, 0x4000, NAND_BUSWIDTH_16,"NAND 16MiB 3.3V 16-bit"}, | |||
{ 0x0, 0x35, 512, 32, 0x4000, 0, "NAND 32MiB 1.8V 8-bit"}, | |||
{ 0x0, 0x75, 512, 32, 0x4000, 0, "NAND 32MiB 3.3V 8-bit"}, | |||
{ 0x0, 0x45, 512, 32, 0x4000, NAND_BUSWIDTH_16,"NAND 32MiB 1.8V 16-bit"}, | |||
{ 0x0, 0x55, 512, 32, 0x4000, NAND_BUSWIDTH_16,"NAND 32MiB 3.3V 16-bit"}, | |||
{ 0x0, 0x36, 512, 64, 0x4000, 0, "NAND 64MiB 1.8V 8-bit"}, | |||
{ 0x0, 0x76, 512, 64, 0x4000, 0, "NAND 64MiB 3.3V 8-bit"}, | |||
{ 0x0, 0x46, 512, 64, 0x4000, NAND_BUSWIDTH_16,"NAND 64MiB 1.8V 16-bit"}, | |||
{ 0x0, 0x56, 512, 64, 0x4000, NAND_BUSWIDTH_16,"NAND 64MiB 3.3V 16-bit"}, | |||
{ 0x0, 0x78, 512, 128, 0x4000, 0, "NAND 128MiB 1.8V 8-bit"}, | |||
{ 0x0, 0x39, 512, 128, 0x4000, 0, "NAND 128MiB 1.8V 8-bit"}, | |||
{ 0x0, 0x79, 512, 128, 0x4000, 0, "NAND 128MiB 3.3V 8-bit"}, | |||
{ 0x0, 0x72, 512, 128, 0x4000, NAND_BUSWIDTH_16,"NAND 128MiB 1.8V 16-bit"}, | |||
{ 0x0, 0x49, 512, 128, 0x4000, NAND_BUSWIDTH_16,"NAND 128MiB 1.8V 16-bit"}, | |||
{ 0x0, 0x74, 512, 128, 0x4000, NAND_BUSWIDTH_16,"NAND 128MiB 3.3V 16-bit"}, | |||
{ 0x0, 0x59, 512, 128, 0x4000, NAND_BUSWIDTH_16,"NAND 128MiB 3.3V 16-bit"}, | |||
{ 0x0, 0x71, 512, 256, 0x4000, 0, "NAND 256MiB 3.3V 8-bit"}, | |||
{ 0x0, 0xA2, 0, 64, 0, LP_OPTIONS, "NAND 64MiB 1.8V 8-bit"}, | |||
{ 0x0, 0xF2, 0, 64, 0, LP_OPTIONS, "NAND 64MiB 3.3V 8-bit"}, | |||
{ 0x0, 0xB2, 0, 64, 0, LP_OPTIONS16, "NAND 64MiB 1.8V 16-bit"}, | |||
{ 0x0, 0xC2, 0, 64, 0, LP_OPTIONS16, "NAND 64MiB 3.3V 16-bit"}, | |||
{ 0x0, 0xA1, 0, 128, 0, LP_OPTIONS, "NAND 128MiB 1.8V 8-bit"}, | |||
{ 0x0, 0xF1, 0, 128, 0, LP_OPTIONS, "NAND 128MiB 3.3V 8-bit"}, | |||
{ 0x0, 0xB1, 0, 128, 0, LP_OPTIONS16, "NAND 128MiB 1.8V 16-bit"}, | |||
{ 0x0, 0xC1, 0, 128, 0, LP_OPTIONS16, "NAND 128MiB 3.3V 16-bit"}, | |||
{ 0x0, 0xAA, 0, 256, 0, LP_OPTIONS, "NAND 256MiB 1.8V 8-bit"}, | |||
{ 0x0, 0xDA, 0, 256, 0, LP_OPTIONS, "NAND 256MiB 3.3V 8-bit"}, | |||
{ 0x0, 0xBA, 0, 256, 0, LP_OPTIONS16, "NAND 256MiB 1.8V 16-bit"}, | |||
{ 0x0, 0xCA, 0, 256, 0, LP_OPTIONS16, "NAND 256MiB 3.3V 16-bit"}, | |||
{ 0x0, 0xAC, 0, 512, 0, LP_OPTIONS, "NAND 512MiB 1.8V 8-bit"}, | |||
{ 0x0, 0xDC, 0, 512, 0, LP_OPTIONS, "NAND 512MiB 3.3V 8-bit"}, | |||
{ 0x0, 0xBC, 0, 512, 0, LP_OPTIONS16, "NAND 512MiB 1.8V 16-bit"}, | |||
{ 0x0, 0xCC, 0, 512, 0, LP_OPTIONS16, "NAND 512MiB 3.3V 16-bit"}, | |||
{ 0x0, 0xA3, 0, 1024, 0, LP_OPTIONS, "NAND 1GiB 1.8V 8-bit"}, | |||
{ 0x0, 0xD3, 0, 1024, 0, LP_OPTIONS, "NAND 1GiB 3.3V 8-bit"}, | |||
{ 0x0, 0xB3, 0, 1024, 0, LP_OPTIONS16, "NAND 1GiB 1.8V 16-bit"}, | |||
{ 0x0, 0xC3, 0, 1024, 0, LP_OPTIONS16, "NAND 1GiB 3.3V 16-bit"}, | |||
{ 0x0, 0xA5, 0, 2048, 0, LP_OPTIONS, "NAND 2GiB 1.8V 8-bit"}, | |||
{ 0x0, 0xD5, 0, 8192, 0, LP_OPTIONS, "NAND 2GiB 3.3V 8-bit"}, | |||
{ 0x0, 0xB5, 0, 2048, 0, LP_OPTIONS16, "NAND 2GiB 1.8V 16-bit"}, | |||
{ 0x0, 0xC5, 0, 2048, 0, LP_OPTIONS16, "NAND 2GiB 3.3V 16-bit"}, | |||
{ 0x0, 0x48, 0, 2048, 0, LP_OPTIONS, "NAND 2GiB 3.3V 8-bit"}, | |||
{ 0x0, 0x33, 512, 16, 0x4000, 0, "NAND 16MiB 1.8V 8-bit"}, | |||
{ 0x0, 0x73, 512, 16, 0x4000, 0, "NAND 16MiB 3.3V 8-bit"}, | |||
{ 0x0, 0x43, 512, 16, 0x4000, NAND_BUSWIDTH_16, "NAND 16MiB 1.8V 16-bit"}, | |||
{ 0x0, 0x53, 512, 16, 0x4000, NAND_BUSWIDTH_16, "NAND 16MiB 3.3V 16-bit"}, | |||
{ 0x0, 0x35, 512, 32, 0x4000, 0, "NAND 32MiB 1.8V 8-bit"}, | |||
{ 0x0, 0x75, 512, 32, 0x4000, 0, "NAND 32MiB 3.3V 8-bit"}, | |||
{ 0x0, 0x45, 512, 32, 0x4000, NAND_BUSWIDTH_16, "NAND 32MiB 1.8V 16-bit"}, | |||
{ 0x0, 0x55, 512, 32, 0x4000, NAND_BUSWIDTH_16, "NAND 32MiB 3.3V 16-bit"}, | |||
{ 0x0, 0x36, 512, 64, 0x4000, 0, "NAND 64MiB 1.8V 8-bit"}, | |||
{ 0x0, 0x76, 512, 64, 0x4000, 0, "NAND 64MiB 3.3V 8-bit"}, | |||
{ 0x0, 0x46, 512, 64, 0x4000, NAND_BUSWIDTH_16, "NAND 64MiB 1.8V 16-bit"}, | |||
{ 0x0, 0x56, 512, 64, 0x4000, NAND_BUSWIDTH_16, "NAND 64MiB 3.3V 16-bit"}, | |||
{ 0x0, 0x78, 512, 128, 0x4000, 0, "NAND 128MiB 1.8V 8-bit"}, | |||
{ 0x0, 0x39, 512, 128, 0x4000, 0, "NAND 128MiB 1.8V 8-bit"}, | |||
{ 0x0, 0x79, 512, 128, 0x4000, 0, "NAND 128MiB 3.3V 8-bit"}, | |||
{ 0x0, 0x72, 512, 128, 0x4000, NAND_BUSWIDTH_16, "NAND 128MiB 1.8V 16-bit"}, | |||
{ 0x0, 0x49, 512, 128, 0x4000, NAND_BUSWIDTH_16, "NAND 128MiB 1.8V 16-bit"}, | |||
{ 0x0, 0x74, 512, 128, 0x4000, NAND_BUSWIDTH_16, "NAND 128MiB 3.3V 16-bit"}, | |||
{ 0x0, 0x59, 512, 128, 0x4000, NAND_BUSWIDTH_16, "NAND 128MiB 3.3V 16-bit"}, | |||
{ 0x0, 0x71, 512, 256, 0x4000, 0, "NAND 256MiB 3.3V 8-bit"}, | |||
{ 0x0, 0xA2, 0, 64, 0, LP_OPTIONS, "NAND 64MiB 1.8V 8-bit"}, | |||
{ 0x0, 0xF2, 0, 64, 0, LP_OPTIONS, "NAND 64MiB 3.3V 8-bit"}, | |||
{ 0x0, 0xB2, 0, 64, 0, LP_OPTIONS16, "NAND 64MiB 1.8V 16-bit"}, | |||
{ 0x0, 0xC2, 0, 64, 0, LP_OPTIONS16, "NAND 64MiB 3.3V 16-bit"}, | |||
{ 0x0, 0xA1, 0, 128, 0, LP_OPTIONS, "NAND 128MiB 1.8V 8-bit"}, | |||
{ 0x0, 0xF1, 0, 128, 0, LP_OPTIONS, "NAND 128MiB 3.3V 8-bit"}, | |||
{ 0x0, 0xB1, 0, 128, 0, LP_OPTIONS16, "NAND 128MiB 1.8V 16-bit"}, | |||
{ 0x0, 0xC1, 0, 128, 0, LP_OPTIONS16, "NAND 128MiB 3.3V 16-bit"}, | |||
{ 0x0, 0xAA, 0, 256, 0, LP_OPTIONS, "NAND 256MiB 1.8V 8-bit"}, | |||
{ 0x0, 0xDA, 0, 256, 0, LP_OPTIONS, "NAND 256MiB 3.3V 8-bit"}, | |||
{ 0x0, 0xBA, 0, 256, 0, LP_OPTIONS16, "NAND 256MiB 1.8V 16-bit"}, | |||
{ 0x0, 0xCA, 0, 256, 0, LP_OPTIONS16, "NAND 256MiB 3.3V 16-bit"}, | |||
{ 0x0, 0xAC, 0, 512, 0, LP_OPTIONS, "NAND 512MiB 1.8V 8-bit"}, | |||
{ 0x0, 0xDC, 0, 512, 0, LP_OPTIONS, "NAND 512MiB 3.3V 8-bit"}, | |||
{ 0x0, 0xBC, 0, 512, 0, LP_OPTIONS16, "NAND 512MiB 1.8V 16-bit"}, | |||
{ 0x0, 0xCC, 0, 512, 0, LP_OPTIONS16, "NAND 512MiB 3.3V 16-bit"}, | |||
{ 0x0, 0xA3, 0, 1024, 0, LP_OPTIONS, "NAND 1GiB 1.8V 8-bit"}, | |||
{ 0x0, 0xD3, 0, 1024, 0, LP_OPTIONS, "NAND 1GiB 3.3V 8-bit"}, | |||
{ 0x0, 0xB3, 0, 1024, 0, LP_OPTIONS16, "NAND 1GiB 1.8V 16-bit"}, | |||
{ 0x0, 0xC3, 0, 1024, 0, LP_OPTIONS16, "NAND 1GiB 3.3V 16-bit"}, | |||
{ 0x0, 0xA5, 0, 2048, 0, LP_OPTIONS, "NAND 2GiB 1.8V 8-bit"}, | |||
{ 0x0, 0xD5, 0, 8192, 0, LP_OPTIONS, "NAND 2GiB 3.3V 8-bit"}, | |||
{ 0x0, 0xB5, 0, 2048, 0, LP_OPTIONS16, "NAND 2GiB 1.8V 16-bit"}, | |||
{ 0x0, 0xC5, 0, 2048, 0, LP_OPTIONS16, "NAND 2GiB 3.3V 16-bit"}, | |||
{ 0x0, 0x48, 0, 2048, 0, LP_OPTIONS, "NAND 2GiB 3.3V 8-bit"}, | |||
{0, 0, 0, 0, 0, 0, NULL} | |||
}; | |||
/* Manufacturer ID list | |||
*/ | |||
static struct nand_manufacturer nand_manuf_ids[] = | |||
{ | |||
static struct nand_manufacturer nand_manuf_ids[] = { | |||
{0x0, "unknown"}, | |||
{NAND_MFR_TOSHIBA, "Toshiba"}, | |||
{NAND_MFR_SAMSUNG, "Samsung"}, | |||
@@ -162,7 +164,8 @@ static struct nand_ecclayout nand_oob_8 = { | |||
{.offset = 3, | |||
.length = 2}, | |||
{.offset = 6, | |||
.length = 2}} | |||
.length = 2} | |||
} | |||
}; | |||
#endif | |||
@@ -179,8 +182,7 @@ static struct nand_device *get_nand_device_by_name(const char *name) | |||
unsigned found = 0; | |||
struct nand_device *nand; | |||
for (nand = nand_devices; NULL != nand; nand = nand->next) | |||
{ | |||
for (nand = nand_devices; NULL != nand; nand = nand->next) { | |||
if (strcmp(nand->name, name) == 0) | |||
return nand; | |||
if (!flash_driver_name_matches(nand->controller->name, name)) | |||
@@ -197,19 +199,16 @@ struct nand_device *get_nand_device_by_num(int num) | |||
struct nand_device *p; | |||
int i = 0; | |||
for (p = nand_devices; p; p = p->next) | |||
{ | |||
for (p = nand_devices; p; p = p->next) { | |||
if (i++ == num) | |||
{ | |||
return p; | |||
} | |||
} | |||
return NULL; | |||
} | |||
COMMAND_HELPER(nand_command_get_device, unsigned name_index, | |||
struct nand_device **nand) | |||
struct nand_device **nand) | |||
{ | |||
const char *str = CMD_ARGV[name_index]; | |||
*nand = get_nand_device_by_name(str); | |||
@@ -241,23 +240,18 @@ int nand_build_bbt(struct nand_device *nand, int first, int last) | |||
last = nand->num_blocks - 1; | |||
page = first * pages_per_block; | |||
for (i = first; i <= last; i++) | |||
{ | |||
for (i = first; i <= last; i++) { | |||
ret = nand_read_page(nand, page, NULL, 0, oob, 6); | |||
if (ret != ERROR_OK) | |||
return ret; | |||
if (((nand->device->options & NAND_BUSWIDTH_16) && ((oob[0] & oob[1]) != 0xff)) | |||
|| (((nand->page_size == 512) && (oob[5] != 0xff)) || | |||
((nand->page_size == 2048) && (oob[0] != 0xff)))) | |||
{ | |||
|| (((nand->page_size == 512) && (oob[5] != 0xff)) || | |||
((nand->page_size == 2048) && (oob[0] != 0xff)))) { | |||
LOG_WARNING("bad block: %i", i); | |||
nand->blocks[i].is_bad = 1; | |||
} | |||
else | |||
{ | |||
} else | |||
nand->blocks[i].is_bad = 0; | |||
} | |||
page += pages_per_block; | |||
} | |||
@@ -276,16 +270,12 @@ int nand_read_status(struct nand_device *nand, uint8_t *status) | |||
alive_sleep(1); | |||
/* read status */ | |||
if (nand->device->options & NAND_BUSWIDTH_16) | |||
{ | |||
if (nand->device->options & NAND_BUSWIDTH_16) { | |||
uint16_t data; | |||
nand->controller->read_data(nand, &data); | |||
*status = data & 0xff; | |||
} | |||
else | |||
{ | |||
} else | |||
nand->controller->read_data(nand, status); | |||
} | |||
return ERROR_OK; | |||
} | |||
@@ -300,9 +290,8 @@ static int nand_poll_ready(struct nand_device *nand, int timeout) | |||
uint16_t data; | |||
nand->controller->read_data(nand, &data); | |||
status = data & 0xff; | |||
} else { | |||
} else | |||
nand->controller->read_data(nand, &status); | |||
} | |||
if (status & NAND_STATUS_READY) | |||
break; | |||
alive_sleep(1); | |||
@@ -329,15 +318,15 @@ int nand_probe(struct nand_device *nand) | |||
nand->erase_size = 0; | |||
/* initialize controller (device parameters are zero, use controller default) */ | |||
if ((retval = nand->controller->init(nand) != ERROR_OK)) | |||
{ | |||
switch (retval) | |||
{ | |||
retval = nand->controller->init(nand); | |||
if (retval != ERROR_OK) { | |||
switch (retval) { | |||
case ERROR_NAND_OPERATION_FAILED: | |||
LOG_DEBUG("controller initialization failed"); | |||
return ERROR_NAND_OPERATION_FAILED; | |||
case ERROR_NAND_OPERATION_NOT_SUPPORTED: | |||
LOG_ERROR("BUG: controller reported that it doesn't support default parameters"); | |||
LOG_ERROR( | |||
"BUG: controller reported that it doesn't support default parameters"); | |||
return ERROR_NAND_OPERATION_FAILED; | |||
default: | |||
LOG_ERROR("BUG: unknown controller initialization failure"); | |||
@@ -351,13 +340,10 @@ int nand_probe(struct nand_device *nand) | |||
nand->controller->command(nand, NAND_CMD_READID); | |||
nand->controller->address(nand, 0x0); | |||
if (nand->bus_width == 8) | |||
{ | |||
if (nand->bus_width == 8) { | |||
nand->controller->read_data(nand, &manufacturer_id); | |||
nand->controller->read_data(nand, &device_id); | |||
} | |||
else | |||
{ | |||
} else { | |||
uint16_t data_buf; | |||
nand->controller->read_data(nand, &data_buf); | |||
manufacturer_id = data_buf & 0xff; | |||
@@ -365,36 +351,32 @@ int nand_probe(struct nand_device *nand) | |||
device_id = data_buf & 0xff; | |||
} | |||
for (i = 0; nand_flash_ids[i].name; i++) | |||
{ | |||
for (i = 0; nand_flash_ids[i].name; i++) { | |||
if (nand_flash_ids[i].id == device_id && | |||
(nand_flash_ids[i].mfr_id == manufacturer_id || | |||
nand_flash_ids[i].mfr_id == 0 )) | |||
{ | |||
(nand_flash_ids[i].mfr_id == manufacturer_id || | |||
nand_flash_ids[i].mfr_id == 0)) { | |||
nand->device = &nand_flash_ids[i]; | |||
break; | |||
} | |||
} | |||
for (i = 0; nand_manuf_ids[i].name; i++) | |||
{ | |||
if (nand_manuf_ids[i].id == manufacturer_id) | |||
{ | |||
for (i = 0; nand_manuf_ids[i].name; i++) { | |||
if (nand_manuf_ids[i].id == manufacturer_id) { | |||
nand->manufacturer = &nand_manuf_ids[i]; | |||
break; | |||
} | |||
} | |||
if (!nand->manufacturer) | |||
{ | |||
if (!nand->manufacturer) { | |||
nand->manufacturer = &nand_manuf_ids[0]; | |||
nand->manufacturer->id = manufacturer_id; | |||
} | |||
if (!nand->device) | |||
{ | |||
LOG_ERROR("unknown NAND flash device found, manufacturer id: 0x%2.2x device id: 0x%2.2x", | |||
manufacturer_id, device_id); | |||
if (!nand->device) { | |||
LOG_ERROR( | |||
"unknown NAND flash device found, manufacturer id: 0x%2.2x device id: 0x%2.2x", | |||
manufacturer_id, | |||
device_id); | |||
return ERROR_NAND_OPERATION_FAILED; | |||
} | |||
@@ -410,16 +392,12 @@ int nand_probe(struct nand_device *nand) | |||
/* Do we need extended device probe information? */ | |||
if (nand->device->page_size == 0 || | |||
nand->device->erase_size == 0) | |||
{ | |||
if (nand->bus_width == 8) | |||
{ | |||
nand->device->erase_size == 0) { | |||
if (nand->bus_width == 8) { | |||
nand->controller->read_data(nand, id_buff + 3); | |||
nand->controller->read_data(nand, id_buff + 4); | |||
nand->controller->read_data(nand, id_buff + 5); | |||
} | |||
else | |||
{ | |||
} else { | |||
uint16_t data_buf; | |||
nand->controller->read_data(nand, &data_buf); | |||
@@ -435,81 +413,68 @@ int nand_probe(struct nand_device *nand) | |||
/* page size */ | |||
if (nand->device->page_size == 0) | |||
{ | |||
nand->page_size = 1 << (10 + (id_buff[4] & 3)); | |||
} | |||
else if (nand->device->page_size == 256) | |||
{ | |||
else if (nand->device->page_size == 256) { | |||
LOG_ERROR("NAND flashes with 256 byte pagesize are not supported"); | |||
return ERROR_NAND_OPERATION_FAILED; | |||
} | |||
else | |||
{ | |||
} else | |||
nand->page_size = nand->device->page_size; | |||
} | |||
/* number of address cycles */ | |||
if (nand->page_size <= 512) | |||
{ | |||
if (nand->page_size <= 512) { | |||
/* small page devices */ | |||
if (nand->device->chip_size <= 32) | |||
nand->address_cycles = 3; | |||
else if (nand->device->chip_size <= 8*1024) | |||
nand->address_cycles = 4; | |||
else | |||
{ | |||
else { | |||
LOG_ERROR("BUG: small page NAND device with more than 8 GiB encountered"); | |||
nand->address_cycles = 5; | |||
} | |||
} | |||
else | |||
{ | |||
} else { | |||
/* large page devices */ | |||
if (nand->device->chip_size <= 128) | |||
nand->address_cycles = 4; | |||
else if (nand->device->chip_size <= 32*1024) | |||
nand->address_cycles = 5; | |||
else | |||
{ | |||
else { | |||
LOG_ERROR("BUG: large page NAND device with more than 32 GiB encountered"); | |||
nand->address_cycles = 6; | |||
} | |||
} | |||
/* erase size */ | |||
if (nand->device->erase_size == 0) | |||
{ | |||
if (nand->device->erase_size == 0) { | |||
switch ((id_buff[4] >> 4) & 3) { | |||
case 0: | |||
nand->erase_size = 64 << 10; | |||
break; | |||
case 1: | |||
nand->erase_size = 128 << 10; | |||
break; | |||
case 2: | |||
nand->erase_size = 256 << 10; | |||
break; | |||
case 3: | |||
nand->erase_size =512 << 10; | |||
break; | |||
case 0: | |||
nand->erase_size = 64 << 10; | |||
break; | |||
case 1: | |||
nand->erase_size = 128 << 10; | |||
break; | |||
case 2: | |||
nand->erase_size = 256 << 10; | |||
break; | |||
case 3: | |||
nand->erase_size = 512 << 10; | |||
break; | |||
} | |||
} | |||
else | |||
{ | |||
} else | |||
nand->erase_size = nand->device->erase_size; | |||
} | |||
/* initialize controller, but leave parameters at the controllers default */ | |||
if ((retval = nand->controller->init(nand) != ERROR_OK)) | |||
{ | |||
switch (retval) | |||
{ | |||
retval = nand->controller->init(nand); | |||
if (retval != ERROR_OK) { | |||
switch (retval) { | |||
case ERROR_NAND_OPERATION_FAILED: | |||
LOG_DEBUG("controller initialization failed"); | |||
return ERROR_NAND_OPERATION_FAILED; | |||
case ERROR_NAND_OPERATION_NOT_SUPPORTED: | |||
LOG_ERROR("controller doesn't support requested parameters (buswidth: %i, address cycles: %i, page size: %i)", | |||
nand->bus_width, nand->address_cycles, nand->page_size); | |||
LOG_ERROR( | |||
"controller doesn't support requested parameters (buswidth: %i, address cycles: %i, page size: %i)", | |||
nand->bus_width, | |||
nand->address_cycles, | |||
nand->page_size); | |||
return ERROR_NAND_OPERATION_FAILED; | |||
default: | |||
LOG_ERROR("BUG: unknown controller initialization failure"); | |||
@@ -520,8 +485,7 @@ int nand_probe(struct nand_device *nand) | |||
nand->num_blocks = (nand->device->chip_size * 1024) / (nand->erase_size / 1024); | |||
nand->blocks = malloc(sizeof(struct nand_block) * nand->num_blocks); | |||
for (i = 0; i < nand->num_blocks; i++) | |||
{ | |||
for (i = 0; i < nand->num_blocks; i++) { | |||
nand->blocks[i].size = nand->erase_size; | |||
nand->blocks[i].offset = i * nand->erase_size; | |||
nand->blocks[i].is_erased = -1; | |||
@@ -545,25 +509,21 @@ int nand_erase(struct nand_device *nand, int first_block, int last_block) | |||
return ERROR_COMMAND_SYNTAX_ERROR; | |||
/* make sure we know if a block is bad before erasing it */ | |||
for (i = first_block; i <= last_block; i++) | |||
{ | |||
if (nand->blocks[i].is_bad == -1) | |||
{ | |||
for (i = first_block; i <= last_block; i++) { | |||
if (nand->blocks[i].is_bad == -1) { | |||
nand_build_bbt(nand, i, last_block); | |||
break; | |||
} | |||
} | |||
for (i = first_block; i <= last_block; i++) | |||
{ | |||
for (i = first_block; i <= last_block; i++) { | |||
/* Send erase setup command */ | |||
nand->controller->command(nand, NAND_CMD_ERASE1); | |||
page = i * (nand->erase_size / nand->page_size); | |||
/* Send page address */ | |||
if (nand->page_size <= 512) | |||
{ | |||
if (nand->page_size <= 512) { | |||
/* row */ | |||
nand->controller->address(nand, page & 0xff); | |||
nand->controller->address(nand, (page >> 8) & 0xff); | |||
@@ -575,9 +535,7 @@ int nand_erase(struct nand_device *nand, int first_block, int last_block) | |||
/* 4th cycle only on devices with more than 8 GiB */ | |||
if (nand->address_cycles >= 5) | |||
nand->controller->address(nand, (page >> 24) & 0xff); | |||
} | |||
else | |||
{ | |||
} else { | |||
/* row */ | |||
nand->controller->address(nand, page & 0xff); | |||
nand->controller->address(nand, (page >> 8) & 0xff); | |||
@@ -591,26 +549,24 @@ int nand_erase(struct nand_device *nand, int first_block, int last_block) | |||
nand->controller->command(nand, NAND_CMD_ERASE2); | |||
retval = nand->controller->nand_ready ? | |||
nand->controller->nand_ready(nand, 1000) : | |||
nand_poll_ready(nand, 1000); | |||
nand->controller->nand_ready(nand, 1000) : | |||
nand_poll_ready(nand, 1000); | |||
if (!retval) { | |||
LOG_ERROR("timeout waiting for NAND flash block erase to complete"); | |||
return ERROR_NAND_OPERATION_TIMEOUT; | |||
} | |||
retval = nand_read_status(nand, &status); | |||
if (retval != ERROR_OK) | |||
{ | |||
if (retval != ERROR_OK) { | |||
LOG_ERROR("couldn't read status"); | |||
return ERROR_NAND_OPERATION_FAILED; | |||
} | |||
if (status & 0x1) | |||
{ | |||
if (status & 0x1) { | |||
LOG_ERROR("didn't erase %sblock %d; status: 0x%2.2x", | |||
(nand->blocks[i].is_bad == 1) | |||
? "bad " : "", | |||
i, status); | |||
(nand->blocks[i].is_bad == 1) | |||
? "bad " : "", | |||
i, status); | |||
/* continue; other blocks might still be erasable */ | |||
} | |||
@@ -621,23 +577,24 @@ int nand_erase(struct nand_device *nand, int first_block, int last_block) | |||
} | |||
#if 0 | |||
static int nand_read_plain(struct nand_device *nand, uint32_t address, uint8_t *data, uint32_t data_size) | |||
static int nand_read_plain(struct nand_device *nand, | |||
uint32_t address, | |||
uint8_t *data, | |||
uint32_t data_size) | |||
{ | |||
uint8_t *page; | |||
if (!nand->device) | |||
return ERROR_NAND_DEVICE_NOT_PROBED; | |||
if (address % nand->page_size) | |||
{ | |||
if (address % nand->page_size) { | |||
LOG_ERROR("reads need to be page aligned"); | |||
return ERROR_NAND_OPERATION_FAILED; | |||
} | |||
page = malloc(nand->page_size); | |||
while (data_size > 0) | |||
{ | |||
while (data_size > 0) { | |||
uint32_t thisrun_size = (data_size > nand->page_size) ? nand->page_size : data_size; | |||
uint32_t page_address; | |||
@@ -658,23 +615,24 @@ static int nand_read_plain(struct nand_device *nand, uint32_t address, uint8_t * | |||
return ERROR_OK; | |||
} | |||
static int nand_write_plain(struct nand_device *nand, uint32_t address, uint8_t *data, uint32_t data_size) | |||
static int nand_write_plain(struct nand_device *nand, | |||
uint32_t address, | |||
uint8_t *data, | |||
uint32_t data_size) | |||
{ | |||
uint8_t *page; | |||
if (!nand->device) | |||
return ERROR_NAND_DEVICE_NOT_PROBED; | |||
if (address % nand->page_size) | |||
{ | |||
if (address % nand->page_size) { | |||
LOG_ERROR("writes need to be page aligned"); | |||
return ERROR_NAND_OPERATION_FAILED; | |||
} | |||
page = malloc(nand->page_size); | |||
while (data_size > 0) | |||
{ | |||
while (data_size > 0) { | |||
uint32_t thisrun_size = (data_size > nand->page_size) ? nand->page_size : data_size; | |||
uint32_t page_address; | |||
@@ -697,8 +655,8 @@ static int nand_write_plain(struct nand_device *nand, uint32_t address, uint8_t | |||
#endif | |||
int nand_write_page(struct nand_device *nand, uint32_t page, | |||
uint8_t *data, uint32_t data_size, | |||
uint8_t *oob, uint32_t oob_size) | |||
uint8_t *data, uint32_t data_size, | |||
uint8_t *oob, uint32_t oob_size) | |||
{ | |||
uint32_t block; | |||
@@ -716,8 +674,8 @@ int nand_write_page(struct nand_device *nand, uint32_t page, | |||
} | |||
int nand_read_page(struct nand_device *nand, uint32_t page, | |||
uint8_t *data, uint32_t data_size, | |||
uint8_t *oob, uint32_t oob_size) | |||
uint8_t *data, uint32_t data_size, | |||
uint8_t *oob, uint32_t oob_size) | |||
{ | |||
if (!nand->device) | |||
return ERROR_NAND_DEVICE_NOT_PROBED; | |||
@@ -729,7 +687,7 @@ int nand_read_page(struct nand_device *nand, uint32_t page, | |||
} | |||
int nand_page_command(struct nand_device *nand, uint32_t page, | |||
uint8_t cmd, bool oob_only) | |||
uint8_t cmd, bool oob_only) | |||
{ | |||
if (!nand->device) | |||
return ERROR_NAND_DEVICE_NOT_PROBED; | |||
@@ -814,8 +772,8 @@ int nand_read_data_page(struct nand_device *nand, uint8_t *data, uint32_t size) | |||
} | |||
int nand_read_page_raw(struct nand_device *nand, uint32_t page, | |||
uint8_t *data, uint32_t data_size, | |||
uint8_t *oob, uint32_t oob_size) | |||
uint8_t *data, uint32_t data_size, | |||
uint8_t *oob, uint32_t oob_size) | |||
{ | |||
int retval; | |||
@@ -870,8 +828,8 @@ int nand_write_finish(struct nand_device *nand) | |||
nand->controller->command(nand, NAND_CMD_PAGEPROG); | |||
retval = nand->controller->nand_ready ? | |||
nand->controller->nand_ready(nand, 100) : | |||
nand_poll_ready(nand, 100); | |||
nand->controller->nand_ready(nand, 100) : | |||
nand_poll_ready(nand, 100); | |||
if (!retval) | |||
return ERROR_NAND_OPERATION_TIMEOUT; | |||
@@ -883,7 +841,7 @@ int nand_write_finish(struct nand_device *nand) | |||
if (status & NAND_STATUS_FAIL) { | |||
LOG_ERROR("write operation didn't pass, status: 0x%2.2x", | |||
status); | |||
status); | |||
return ERROR_NAND_OPERATION_FAILED; | |||
} | |||
@@ -891,8 +849,8 @@ int nand_write_finish(struct nand_device *nand) | |||
} | |||
int nand_write_page_raw(struct nand_device *nand, uint32_t page, | |||
uint8_t *data, uint32_t data_size, | |||
uint8_t *oob, uint32_t oob_size) | |||
uint8_t *data, uint32_t data_size, | |||
uint8_t *oob, uint32_t oob_size) | |||
{ | |||
int retval; | |||
@@ -918,4 +876,3 @@ int nand_write_page_raw(struct nand_device *nand, uint32_t page, | |||
return nand_write_finish(nand); | |||
} | |||
@@ -22,6 +22,7 @@ | |||
* Free Software Foundation, Inc., * | |||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * | |||
***************************************************************************/ | |||
#ifndef FLASH_NAND_CORE_H | |||
#define FLASH_NAND_CORE_H | |||
@@ -30,8 +31,7 @@ | |||
/** | |||
* Representation of a single NAND block in a NAND device. | |||
*/ | |||
struct nand_block | |||
{ | |||
struct nand_block { | |||
/** Offset to the block. */ | |||
uint32_t offset; | |||
@@ -57,8 +57,7 @@ struct nand_ecclayout { | |||
struct nand_oobfree oobfree[2]; | |||
}; | |||
struct nand_device | |||
{ | |||
struct nand_device { | |||
const char *name; | |||
struct target *target; | |||
struct nand_flash_controller *controller; | |||
@@ -77,8 +76,7 @@ struct nand_device | |||
/* NAND Flash Manufacturer ID Codes | |||
*/ | |||
enum | |||
{ | |||
enum { | |||
NAND_MFR_TOSHIBA = 0x98, | |||
NAND_MFR_SAMSUNG = 0xec, | |||
NAND_MFR_FUJITSU = 0x04, | |||
@@ -89,14 +87,12 @@ enum | |||
NAND_MFR_MICRON = 0x2c, | |||
}; | |||
struct nand_manufacturer | |||
{ | |||
struct nand_manufacturer { | |||
int id; | |||
const char *name; | |||
}; | |||
struct nand_info | |||
{ | |||
struct nand_info { | |||
int mfr_id; | |||
int id; | |||
int page_size; | |||
@@ -152,8 +148,7 @@ enum { | |||
LP_OPTIONS16 = (LP_OPTIONS | NAND_BUSWIDTH_16), | |||
}; | |||
enum | |||
{ | |||
enum { | |||
/* Standard NAND flash commands */ | |||
NAND_CMD_READ0 = 0x0, | |||
NAND_CMD_READ1 = 0x1, | |||
@@ -161,7 +156,7 @@ enum | |||
NAND_CMD_PAGEPROG = 0x10, | |||
NAND_CMD_READOOB = 0x50, | |||
NAND_CMD_ERASE1 = 0x60, | |||
NAND_CMD_STATUS = 0x70, | |||
NAND_CMD_STATUS = 0x70, | |||
NAND_CMD_STATUS_MULTI = 0x71, | |||
NAND_CMD_SEQIN = 0x80, | |||
NAND_CMD_RNDIN = 0x85, | |||
@@ -176,8 +171,7 @@ enum | |||
}; | |||
/* Status bits */ | |||
enum | |||
{ | |||
enum { | |||
NAND_STATUS_FAIL = 0x01, | |||
NAND_STATUS_FAIL_N1 = 0x02, | |||
NAND_STATUS_TRUE_READY = 0x20, | |||
@@ -186,14 +180,14 @@ enum | |||
}; | |||
/* OOB (spare) data formats */ | |||
enum oob_formats | |||
{ | |||
enum oob_formats { | |||
NAND_OOB_NONE = 0x0, /* no OOB data at all */ | |||
NAND_OOB_RAW = 0x1, /* raw OOB data (16 bytes for 512b page sizes, 64 bytes for 2048b page sizes) */ | |||
NAND_OOB_RAW = 0x1, /* raw OOB data (16 bytes for 512b page sizes, 64 bytes for | |||
*2048b page sizes) */ | |||
NAND_OOB_ONLY = 0x2, /* only OOB data */ | |||
NAND_OOB_SW_ECC = 0x10, /* when writing, use SW ECC (as opposed to no ECC) */ | |||
NAND_OOB_HW_ECC = 0x20, /* when writing, use HW ECC (as opposed to no ECC) */ | |||
NAND_OOB_SW_ECC_KW = 0x40, /* when writing, use Marvell's Kirkwood bootrom format */ | |||
NAND_OOB_HW_ECC = 0x20, /* when writing, use HW ECC (as opposed to no ECC) */ | |||
NAND_OOB_SW_ECC_KW = 0x40, /* when writing, use Marvell's Kirkwood bootrom format */ | |||
NAND_OOB_JFFS2 = 0x100, /* when writing, use JFFS2 OOB layout */ | |||
NAND_OOB_YAFFS2 = 0x100,/* when writing, use YAFFS2 OOB layout */ | |||
}; | |||
@@ -202,40 +196,39 @@ enum oob_formats | |||
struct nand_device *get_nand_device_by_num(int num); | |||
int nand_page_command(struct nand_device *nand, uint32_t page, | |||
uint8_t cmd, bool oob_only); | |||
uint8_t cmd, bool oob_only); | |||
int nand_read_data_page(struct nand_device *nand, uint8_t *data, uint32_t size); | |||
int nand_write_data_page(struct nand_device *nand, | |||
uint8_t *data, uint32_t size); | |||
uint8_t *data, uint32_t size); | |||
int nand_write_finish(struct nand_device *nand); | |||
int nand_read_page_raw(struct nand_device *nand, uint32_t page, | |||
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size); | |||
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size); | |||
int nand_write_page_raw(struct nand_device *nand, uint32_t page, | |||
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size); | |||
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size); | |||
int nand_read_status(struct nand_device *nand, uint8_t *status); | |||
int nand_calculate_ecc(struct nand_device *nand, | |||
const uint8_t *dat, uint8_t *ecc_code); | |||
const uint8_t *dat, uint8_t *ecc_code); | |||
int nand_calculate_ecc_kw(struct nand_device *nand, | |||
const uint8_t *dat, uint8_t *ecc_code); | |||
const uint8_t *dat, uint8_t *ecc_code); | |||
int nand_register_commands(struct command_context *cmd_ctx); | |||
/// helper for parsing a nand device command argument string | |||
/* / helper for parsing a nand device command argument string */ | |||
COMMAND_HELPER(nand_command_get_device, unsigned name_index, | |||
struct nand_device **nand); | |||
struct nand_device **nand); | |||
#define ERROR_NAND_DEVICE_INVALID (-1100) | |||
#define ERROR_NAND_OPERATION_FAILED (-1101) | |||
#define ERROR_NAND_OPERATION_TIMEOUT (-1102) | |||
#define ERROR_NAND_OPERATION_NOT_SUPPORTED (-1103) | |||
#define ERROR_NAND_DEVICE_NOT_PROBED (-1104) | |||
#define ERROR_NAND_ERROR_CORRECTION_FAILED (-1105) | |||
#define ERROR_NAND_NO_BUFFER (-1106) | |||
#endif // FLASH_NAND_CORE_H | |||
#define ERROR_NAND_DEVICE_INVALID (-1100) | |||
#define ERROR_NAND_OPERATION_FAILED (-1101) | |||
#define ERROR_NAND_OPERATION_TIMEOUT (-1102) | |||
#define ERROR_NAND_OPERATION_NOT_SUPPORTED (-1103) | |||
#define ERROR_NAND_DEVICE_NOT_PROBED (-1104) | |||
#define ERROR_NAND_ERROR_CORRECTION_FAILED (-1105) | |||
#define ERROR_NAND_NO_BUFFER (-1106) | |||
#endif /* FLASH_NAND_CORE_H */ |
@@ -39,34 +39,34 @@ enum ecc { | |||
}; | |||
struct davinci_nand { | |||
uint8_t chipsel; /* chipselect 0..3 == CS2..CS5 */ | |||
uint8_t eccmode; | |||
uint8_t chipsel; /* chipselect 0..3 == CS2..CS5 */ | |||
uint8_t eccmode; | |||
/* Async EMIF controller base */ | |||
uint32_t aemif; | |||
uint32_t aemif; | |||
/* NAND chip addresses */ | |||
uint32_t data; /* without CLE or ALE */ | |||
uint32_t cmd; /* with CLE */ | |||
uint32_t addr; /* with ALE */ | |||
uint32_t data; /* without CLE or ALE */ | |||
uint32_t cmd; /* with CLE */ | |||
uint32_t addr; /* with ALE */ | |||
/* write acceleration */ | |||
struct arm_nand_data io; | |||
struct arm_nand_data io; | |||
/* page i/o for the relevant flavor of hardware ECC */ | |||
int (*read_page)(struct nand_device *nand, uint32_t page, | |||
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size); | |||
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size); | |||
int (*write_page)(struct nand_device *nand, uint32_t page, | |||
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size); | |||
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size); | |||
}; | |||
#define NANDFCR 0x60 /* flash control register */ | |||
#define NANDFSR 0x64 /* flash status register */ | |||
#define NANDFECC 0x70 /* 1-bit ECC data, CS0, 1st of 4 */ | |||
#define NAND4BITECCLOAD 0xbc /* 4-bit ECC, load saved values */ | |||
#define NAND4BITECC 0xc0 /* 4-bit ECC data, 1st of 4 */ | |||
#define NANDERRADDR 0xd0 /* 4-bit ECC err addr, 1st of 2 */ | |||
#define NANDERRVAL 0xd8 /* 4-bit ECC err value, 1st of 2 */ | |||
#define NANDFCR 0x60 /* flash control register */ | |||
#define NANDFSR 0x64 /* flash status register */ | |||
#define NANDFECC 0x70 /* 1-bit ECC data, CS0, 1st of 4 */ | |||
#define NAND4BITECCLOAD 0xbc /* 4-bit ECC, load saved values */ | |||
#define NAND4BITECC 0xc0 /* 4-bit ECC data, 1st of 4 */ | |||
#define NANDERRADDR 0xd0 /* 4-bit ECC err addr, 1st of 2 */ | |||
#define NANDERRVAL 0xd8 /* 4-bit ECC err value, 1st of 2 */ | |||
static int halted(struct target *target, const char *label) | |||
{ | |||
@@ -181,7 +181,7 @@ static int davinci_read_data(struct nand_device *nand, void *data) | |||
/* REVISIT a bit of native code should let block reads be MUCH faster */ | |||
static int davinci_read_block_data(struct nand_device *nand, | |||
uint8_t *data, int data_size) | |||
uint8_t *data, int data_size) | |||
{ | |||
struct davinci_nand *info = nand->controller_priv; | |||
struct target *target = nand->target; | |||
@@ -214,7 +214,7 @@ static int davinci_read_block_data(struct nand_device *nand, | |||
} | |||
static int davinci_write_block_data(struct nand_device *nand, | |||
uint8_t *data, int data_size) | |||
uint8_t *data, int data_size) | |||
{ | |||
struct davinci_nand *info = nand->controller_priv; | |||
struct target *target = nand->target; | |||
@@ -250,7 +250,7 @@ static int davinci_write_block_data(struct nand_device *nand, | |||
} | |||
static int davinci_write_page(struct nand_device *nand, uint32_t page, | |||
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) | |||
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) | |||
{ | |||
struct davinci_nand *info = nand->controller_priv; | |||
uint8_t *ooballoc = NULL; | |||
@@ -269,17 +269,17 @@ static int davinci_write_page(struct nand_device *nand, uint32_t page, | |||
/* If we're not given OOB, write 0xff where we don't write ECC codes. */ | |||
switch (nand->page_size) { | |||
case 512: | |||
oob_size = 16; | |||
break; | |||
case 2048: | |||
oob_size = 64; | |||
break; | |||
case 4096: | |||
oob_size = 128; | |||
break; | |||
default: | |||
return ERROR_NAND_OPERATION_FAILED; | |||
case 512: | |||
oob_size = 16; | |||
break; | |||
case 2048: | |||
oob_size = 64; | |||
break; | |||
case 4096: | |||
oob_size = 128; | |||
break; | |||
default: | |||
return ERROR_NAND_OPERATION_FAILED; | |||
} | |||
if (!oob) { | |||
ooballoc = malloc(oob_size); | |||
@@ -301,7 +301,7 @@ static int davinci_write_page(struct nand_device *nand, uint32_t page, | |||
} | |||
static int davinci_read_page(struct nand_device *nand, uint32_t page, | |||
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) | |||
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) | |||
{ | |||
struct davinci_nand *info = nand->controller_priv; | |||
@@ -358,7 +358,7 @@ static int davinci_seek_column(struct nand_device *nand, uint16_t column) | |||
} | |||
static int davinci_writepage_tail(struct nand_device *nand, | |||
uint8_t *oob, uint32_t oob_size) | |||
uint8_t *oob, uint32_t oob_size) | |||
{ | |||
struct davinci_nand *info = nand->controller_priv; | |||
struct target *target = nand->target; | |||
@@ -390,7 +390,7 @@ static int davinci_writepage_tail(struct nand_device *nand, | |||
* All DaVinci family chips support 1-bit ECC on a per-chipselect basis. | |||
*/ | |||
static int davinci_write_page_ecc1(struct nand_device *nand, uint32_t page, | |||
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) | |||
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) | |||
{ | |||
unsigned oob_offset; | |||
struct davinci_nand *info = nand->controller_priv; | |||
@@ -404,15 +404,15 @@ static int davinci_write_page_ecc1(struct nand_device *nand, uint32_t page, | |||
* for 16-bit OOB, those extra bytes are discontiguous. | |||
*/ | |||
switch (nand->page_size) { | |||
case 512: | |||
oob_offset = 0; | |||
break; | |||
case 2048: | |||
oob_offset = 40; | |||
break; | |||
default: | |||
oob_offset = 80; | |||
break; | |||
case 512: | |||
oob_offset = 0; | |||
break; | |||
case 2048: | |||
oob_offset = 40; | |||
break; | |||
default: | |||
oob_offset = 80; | |||
break; | |||
} | |||
davinci_write_pagecmd(nand, NAND_CMD_SEQIN, page); | |||
@@ -457,10 +457,10 @@ static int davinci_write_page_ecc1(struct nand_device *nand, uint32_t page, | |||
* manufacturer bad block markers are safe. Contrast: old "infix" style. | |||
*/ | |||
static int davinci_write_page_ecc4(struct nand_device *nand, uint32_t page, | |||
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) | |||
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) | |||
{ | |||
static const uint8_t ecc512[] = { | |||
0, 1, 2, 3, 4, /* 5== mfr badblock */ | |||
0, 1, 2, 3, 4, /* 5== mfr badblock */ | |||
6, 7, /* 8..12 for BBT or JFFS2 */ 13, 14, 15, | |||
}; | |||
static const uint8_t ecc2048[] = { | |||
@@ -470,12 +470,12 @@ static int davinci_write_page_ecc4(struct nand_device *nand, uint32_t page, | |||
54, 55, 56, 57, 58, 59, 60, 61, 62, 63, | |||
}; | |||
static const uint8_t ecc4096[] = { | |||
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, | |||
58, 59, 60, 61, 62, 63, 64, 65, 66, 67, | |||
68, 69, 70, 71, 72, 73, 74, 75, 76, 77, | |||
78, 79, 80, 81, 82, 83, 84, 85, 86, 87, | |||
88, 89, 90, 91, 92, 93, 94, 95, 96, 97, | |||
98, 99, 100, 101, 102, 103, 104, 105, 106, 107, | |||
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, | |||
58, 59, 60, 61, 62, 63, 64, 65, 66, 67, | |||
68, 69, 70, 71, 72, 73, 74, 75, 76, 77, | |||
78, 79, 80, 81, 82, 83, 84, 85, 86, 87, | |||
88, 89, 90, 91, 92, 93, 94, 95, 96, 97, | |||
98, 99, 100, 101, 102, 103, 104, 105, 106, 107, | |||
108, 109, 110, 111, 112, 113, 114, 115, 116, 117, | |||
118, 119, 120, 121, 122, 123, 124, 125, 126, 127, | |||
}; | |||
@@ -495,15 +495,15 @@ static int davinci_write_page_ecc4(struct nand_device *nand, uint32_t page, | |||
* the standard ECC logic can't handle. | |||
*/ | |||
switch (nand->page_size) { | |||
case 512: | |||
l = ecc512; | |||
break; | |||
case 2048: | |||
l = ecc2048; | |||
break; | |||
default: | |||
l = ecc4096; | |||
break; | |||
case 512: | |||
l = ecc512; | |||
break; | |||
case 2048: | |||
l = ecc2048; | |||
break; | |||
default: | |||
l = ecc4096; | |||
break; | |||
} | |||
davinci_write_pagecmd(nand, NAND_CMD_SEQIN, page); | |||
@@ -533,11 +533,11 @@ static int davinci_write_page_ecc4(struct nand_device *nand, uint32_t page, | |||
raw_ecc[i] &= 0x03ff03ff; | |||
} | |||
for (i = 0, p = raw_ecc; i < 2; i++, p += 2) { | |||
oob[*l++] = p[0] & 0xff; | |||
oob[*l++] = p[0] & 0xff; | |||
oob[*l++] = ((p[0] >> 8) & 0x03) | ((p[0] >> 14) & 0xfc); | |||
oob[*l++] = ((p[0] >> 22) & 0x0f) | ((p[1] << 4) & 0xf0); | |||
oob[*l++] = ((p[1] >> 4) & 0x3f) | ((p[1] >> 10) & 0xc0); | |||
oob[*l++] = (p[1] >> 18) & 0xff; | |||
oob[*l++] = (p[1] >> 18) & 0xff; | |||
} | |||
} while (data_size); | |||
@@ -559,7 +559,7 @@ static int davinci_write_page_ecc4(struct nand_device *nand, uint32_t page, | |||
* (MVL 4.x/5.x kernels, filesystems, etc) may need it more generally. | |||
*/ | |||
static int davinci_write_page_ecc4infix(struct nand_device *nand, uint32_t page, | |||
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) | |||
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) | |||
{ | |||
struct davinci_nand *info = nand->controller_priv; | |||
struct target *target = nand->target; | |||
@@ -597,11 +597,11 @@ static int davinci_write_page_ecc4infix(struct nand_device *nand, uint32_t page, | |||
/* skip 6 bytes of prepad, then pack 10 packed ecc bytes */ | |||
for (i = 0, l = oob + 6, p = raw_ecc; i < 2; i++, p += 2) { | |||
*l++ = p[0] & 0xff; | |||
*l++ = p[0] & 0xff; | |||
*l++ = ((p[0] >> 8) & 0x03) | ((p[0] >> 14) & 0xfc); | |||
*l++ = ((p[0] >> 22) & 0x0f) | ((p[1] << 4) & 0xf0); | |||
*l++ = ((p[1] >> 4) & 0x3f) | ((p[1] >> 10) & 0xc0); | |||
*l++ = (p[1] >> 18) & 0xff; | |||
*l++ = (p[1] >> 18) & 0xff; | |||
} | |||
/* write this "out-of-band" data -- infix */ | |||
@@ -616,7 +616,7 @@ static int davinci_write_page_ecc4infix(struct nand_device *nand, uint32_t page, | |||
} | |||
static int davinci_read_page_ecc4infix(struct nand_device *nand, uint32_t page, | |||
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) | |||
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) | |||
{ | |||
int read_size; | |||
int want_col, at_col; | |||
@@ -688,9 +688,8 @@ NAND_DEVICE_COMMAND_HANDLER(davinci_nand_device_command) | |||
* - aemif address | |||
* Plus someday, optionally, ALE and CLE masks. | |||
*/ | |||
if (CMD_ARGC < 5) { | |||
if (CMD_ARGC < 5) | |||
return ERROR_COMMAND_SYNTAX_ERROR; | |||
} | |||
COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[2], chip); | |||
if (chip == 0) { | |||
@@ -720,9 +719,9 @@ NAND_DEVICE_COMMAND_HANDLER(davinci_nand_device_command) | |||
* AEMIF controller address. | |||
*/ | |||
if (aemif == 0x01e00000 /* dm6446, dm357 */ | |||
|| aemif == 0x01e10000 /* dm335, dm355 */ | |||
|| aemif == 0x01d10000 /* dm365 */ | |||
) { | |||
|| aemif == 0x01e10000 /* dm335, dm355 */ | |||
|| aemif == 0x01d10000 /* dm365 */ | |||
) { | |||
if (chip < 0x02000000 || chip >= 0x0a000000) { | |||
LOG_ERROR("NAND address %08lx out of range?", chip); | |||
goto fail; | |||
@@ -757,19 +756,19 @@ NAND_DEVICE_COMMAND_HANDLER(davinci_nand_device_command) | |||
info->read_page = nand_read_page_raw; | |||
switch (eccmode) { | |||
case HWECC1: | |||
/* ECC_HW, 1-bit corrections, 3 bytes ECC per 512 data bytes */ | |||
info->write_page = davinci_write_page_ecc1; | |||
break; | |||
case HWECC4: | |||
/* ECC_HW, 4-bit corrections, 10 bytes ECC per 512 data bytes */ | |||
info->write_page = davinci_write_page_ecc4; | |||
break; | |||
case HWECC4_INFIX: | |||
/* Same 4-bit ECC HW, with problematic page/ecc layout */ | |||
info->read_page = davinci_read_page_ecc4infix; | |||
info->write_page = davinci_write_page_ecc4infix; | |||
break; | |||
case HWECC1: | |||
/* ECC_HW, 1-bit corrections, 3 bytes ECC per 512 data bytes */ | |||
info->write_page = davinci_write_page_ecc1; | |||
break; | |||
case HWECC4: | |||
/* ECC_HW, 4-bit corrections, 10 bytes ECC per 512 data bytes */ | |||
info->write_page = davinci_write_page_ecc4; | |||
break; | |||
case HWECC4_INFIX: | |||
/* Same 4-bit ECC HW, with problematic page/ecc layout */ | |||
info->read_page = davinci_read_page_ecc4infix; | |||
info->write_page = davinci_write_page_ecc4infix; | |||
break; | |||
} | |||
return ERROR_OK; | |||
@@ -779,18 +778,18 @@ fail: | |||
} | |||
struct nand_flash_controller davinci_nand_controller = { | |||
.name = "davinci", | |||
.usage = "chip_addr hwecc_mode aemif_addr", | |||
.nand_device_command = davinci_nand_device_command, | |||
.init = davinci_init, | |||
.reset = davinci_reset, | |||
.command = davinci_command, | |||
.address = davinci_address, | |||
.write_data = davinci_write_data, | |||
.read_data = davinci_read_data, | |||
.write_page = davinci_write_page, | |||
.read_page = davinci_read_page, | |||
.write_block_data = davinci_write_block_data, | |||
.read_block_data = davinci_read_block_data, | |||
.nand_ready = davinci_nand_ready, | |||
.name = "davinci", | |||
.usage = "chip_addr hwecc_mode aemif_addr", | |||
.nand_device_command = davinci_nand_device_command, | |||
.init = davinci_init, | |||
.reset = davinci_reset, | |||
.command = davinci_command, | |||
.address = davinci_address, | |||
.write_data = davinci_write_data, | |||
.read_data = davinci_read_data, | |||
.write_page = davinci_write_page, | |||
.read_page = davinci_read_page, | |||
.write_block_data = davinci_write_block_data, | |||
.read_block_data = davinci_read_block_data, | |||
.nand_ready = davinci_nand_ready, | |||
}; |
@@ -45,8 +45,7 @@ extern struct nand_flash_controller nuc910_nand_controller; | |||
/* extern struct nand_flash_controller boundary_scan_nand_controller; */ | |||
static struct nand_flash_controller *nand_flash_controllers[] = | |||
{ | |||
static struct nand_flash_controller *nand_flash_controllers[] = { | |||
&nonce_nand_controller, | |||
&davinci_nand_controller, | |||
&lpc3180_nand_controller, | |||
@@ -67,8 +66,7 @@ static struct nand_flash_controller *nand_flash_controllers[] = | |||
struct nand_flash_controller *nand_driver_find_by_name(const char *name) | |||
{ | |||
for (unsigned i = 0; nand_flash_controllers[i]; i++) | |||
{ | |||
for (unsigned i = 0; nand_flash_controllers[i]; i++) { | |||
struct nand_flash_controller *controller = nand_flash_controllers[i]; | |||
if (strcmp(name, controller->name) == 0) | |||
return controller; | |||
@@ -77,13 +75,10 @@ struct nand_flash_controller *nand_driver_find_by_name(const char *name) | |||
} | |||
int nand_driver_walk(nand_driver_walker_t f, void *x) | |||
{ | |||
for (unsigned i = 0; nand_flash_controllers[i]; i++) | |||
{ | |||
for (unsigned i = 0; nand_flash_controllers[i]; i++) { | |||
int retval = (*f)(nand_flash_controllers[i], x); | |||
if (ERROR_OK != retval) | |||
return retval; | |||
} | |||
return ERROR_OK; | |||
} | |||
@@ -19,28 +19,28 @@ | |||
* Free Software Foundation, Inc., * | |||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * | |||
***************************************************************************/ | |||
#ifndef FLASH_NAND_DRIVER_H | |||
#define FLASH_NAND_DRIVER_H | |||
struct nand_device; | |||
#define __NAND_DEVICE_COMMAND(name) \ | |||
COMMAND_HELPER(name, struct nand_device *nand) | |||
COMMAND_HELPER(name, struct nand_device *nand) | |||
/** | |||
* Interface for NAND flash controllers. Not all of these functions are | |||
* required for full functionality of the NAND driver, but better performance | |||
* can be achieved by implementing each function. | |||
*/ | |||
struct nand_flash_controller | |||
{ | |||
struct nand_flash_controller { | |||
/** Driver name that is used to select it from configuration files. */ | |||
const char *name; | |||
/** Usage of flash command registration. */ | |||
const char *usage; | |||
const struct command_registration *commands; | |||
const struct command_registration *commands; | |||
/** NAND device command called when driver is instantiated during configuration. */ | |||
__NAND_DEVICE_COMMAND((*nand_device_command)); | |||
@@ -70,10 +70,12 @@ struct nand_flash_controller | |||
int (*read_block_data)(struct nand_device *nand, uint8_t *data, int size); | |||
/** Write a page to the NAND device. */ | |||
int (*write_page)(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size); | |||
int (*write_page)(struct nand_device *nand, uint32_t page, uint8_t *data, | |||
uint32_t data_size, uint8_t *oob, uint32_t oob_size); | |||
/** Read a page from the NAND device. */ | |||
int (*read_page)(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size); | |||
int (*read_page)(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, | |||
uint8_t *oob, uint32_t oob_size); | |||
/** Check if the NAND device is ready for more instructions with timeout. */ | |||
int (*nand_ready)(struct nand_device *nand, int timeout); | |||
@@ -88,8 +90,8 @@ struct nand_flash_controller | |||
*/ | |||
struct nand_flash_controller *nand_driver_find_by_name(const char *name); | |||
/// Signature for callback functions passed to nand_driver_walk | |||
typedef int (*nand_driver_walker_t)(struct nand_flash_controller *c, void*); | |||
/* / Signature for callback functions passed to nand_driver_walk */ | |||
typedef int (*nand_driver_walker_t)(struct nand_flash_controller *c, void *); | |||
/** | |||
* Walk the list of drivers, encapsulating the data structure type. | |||
* Application state/context can be passed through the @c x pointer. | |||
@@ -100,4 +102,4 @@ typedef int (*nand_driver_walker_t)(struct nand_flash_controller *c, void*); | |||
*/ | |||
int nand_driver_walk(nand_driver_walker_t f, void *x); | |||
#endif // FLASH_NAND_DRIVER_H | |||
#endif /* FLASH_NAND_DRIVER_H */ |
@@ -125,7 +125,7 @@ static inline int countbits(uint32_t b) | |||
{ | |||
int res = 0; | |||
for (;b; b >>= 1) | |||
for (; b; b >>= 1) | |||
res += b & 0x01; | |||
return res; | |||
} | |||
@@ -134,7 +134,7 @@ static inline int countbits(uint32_t b) | |||
* nand_correct_data - Detect and correct a 1 bit error for 256 byte block | |||
*/ | |||
int nand_correct_data(struct nand_device *nand, u_char *dat, | |||
u_char *read_ecc, u_char *calc_ecc) | |||
u_char *read_ecc, u_char *calc_ecc) | |||
{ | |||
uint8_t s0, s1, s2; | |||
@@ -151,9 +151,9 @@ int nand_correct_data(struct nand_device *nand, u_char *dat, | |||
return 0; | |||
/* Check for a single bit error */ | |||
if( ((s0 ^ (s0 >> 1)) & 0x55) == 0x55 && | |||
((s1 ^ (s1 >> 1)) & 0x55) == 0x55 && | |||
((s2 ^ (s2 >> 1)) & 0x54) == 0x54) { | |||
if (((s0 ^ (s0 >> 1)) & 0x55) == 0x55 && | |||
((s1 ^ (s1 >> 1)) & 0x55) == 0x55 && | |||
((s2 ^ (s2 >> 1)) & 0x54) == 0x54) { | |||
uint32_t byteoffs, bitnum; | |||
@@ -176,7 +176,7 @@ int nand_correct_data(struct nand_device *nand, u_char *dat, | |||
return 1; | |||
} | |||
if(countbits(s0 | ((uint32_t)s1 << 8) | ((uint32_t)s2 <<16)) == 1) | |||
if (countbits(s0 | ((uint32_t)s1 << 8) | ((uint32_t)s2 << 16)) == 1) | |||
return 1; | |||
return -1; | |||
@@ -28,7 +28,7 @@ | |||
* For multiplication, a discrete log/exponent table is used, with | |||
* primitive element x (F is a primitive field, so x is primitive). | |||
*/ | |||
#define MODPOLY 0x409 /* x^10 + x^3 + 1 in binary */ | |||
#define MODPOLY 0x409 /* x^10 + x^3 + 1 in binary */ | |||
/* | |||
* Maps an integer a [0..1022] to a polynomial b = gf_exp[a] in | |||
@@ -102,7 +102,7 @@ int nand_calculate_ecc_kw(struct nand_device *nand, const uint8_t *data, uint8_t | |||
{ | |||
unsigned int r7, r6, r5, r4, r3, r2, r1, r0; | |||
int i; | |||
static int tables_initialized = 0; | |||
static int tables_initialized; | |||
if (!tables_initialized) { | |||
gf_build_log_exp_table(); | |||
@@ -121,7 +121,6 @@ int nand_calculate_ecc_kw(struct nand_device *nand, const uint8_t *data, uint8_t | |||
r6 = data[510]; | |||
r7 = data[511]; | |||
/* | |||
* Shift bytes 503..0 (in that order) into r0, followed | |||
* by eight zero bytes, while reducing the polynomial by the | |||
@@ -20,6 +20,7 @@ | |||
* Free Software Foundation, Inc., * | |||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * | |||
***************************************************************************/ | |||
#ifdef HAVE_CONFIG_H | |||
#include "config.h" | |||
#endif | |||
@@ -32,18 +33,21 @@ static struct nand_ecclayout nand_oob_16 = { | |||
.eccpos = {0, 1, 2, 3, 6, 7}, | |||
.oobfree = { | |||
{.offset = 8, | |||
. length = 8}} | |||
.length = 8} | |||
} | |||
}; | |||
static struct nand_ecclayout nand_oob_64 = { | |||
.eccbytes = 24, | |||
.eccpos = { | |||
40, 41, 42, 43, 44, 45, 46, 47, | |||
48, 49, 50, 51, 52, 53, 54, 55, | |||
56, 57, 58, 59, 60, 61, 62, 63}, | |||
40, 41, 42, 43, 44, 45, 46, 47, | |||
48, 49, 50, 51, 52, 53, 54, 55, | |||
56, 57, 58, 59, 60, 61, 62, 63 | |||
}, | |||
.oobfree = { | |||
{.offset = 2, | |||
.length = 38}} | |||
.length = 38} | |||
} | |||
}; | |||
void nand_fileio_init(struct nand_fileio_state *state) | |||
@@ -53,45 +57,37 @@ void nand_fileio_init(struct nand_fileio_state *state) | |||
} | |||
int nand_fileio_start(struct command_context *cmd_ctx, | |||
struct nand_device *nand, const char *filename, int filemode, | |||
struct nand_fileio_state *state) | |||
struct nand_device *nand, const char *filename, int filemode, | |||
struct nand_fileio_state *state) | |||
{ | |||
if (state->address % nand->page_size) | |||
{ | |||
if (state->address % nand->page_size) { | |||
command_print(cmd_ctx, "only page-aligned addresses are supported"); | |||
return ERROR_COMMAND_SYNTAX_ERROR; | |||
} | |||
duration_start(&state->bench); | |||
if (NULL != filename) | |||
{ | |||
if (NULL != filename) { | |||
int retval = fileio_open(&state->fileio, filename, filemode, FILEIO_BINARY); | |||
if (ERROR_OK != retval) | |||
{ | |||
if (ERROR_OK != retval) { | |||
const char *msg = (FILEIO_READ == filemode) ? "read" : "write"; | |||
command_print(cmd_ctx, "failed to open '%s' for %s access", | |||
filename, msg); | |||
filename, msg); | |||
return retval; | |||
} | |||
state->file_opened = true; | |||
} | |||
if (!(state->oob_format & NAND_OOB_ONLY)) | |||
{ | |||
if (!(state->oob_format & NAND_OOB_ONLY)) { | |||
state->page_size = nand->page_size; | |||
< |