X-Git-Url: https://review.openocd.org/gitweb?a=blobdiff_plain;f=src%2Fflash%2Fnand%2Fat91sam9.c;h=4341935febc364498568245bbbb7caeaf7058484;hb=28c24a5c41c47a66e9310912f88148814f730a25;hp=92ab047f623a3e9972c3dcc79066d3b48c14805a;hpb=2a76c1bcf94f8ed00c9e744a5405d0ac07cdc85a;p=openocd.git diff --git a/src/flash/nand/at91sam9.c b/src/flash/nand/at91sam9.c index 92ab047f62..4341935feb 100644 --- a/src/flash/nand/at91sam9.c +++ b/src/flash/nand/at91sam9.c @@ -13,10 +13,9 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program. If not, see . */ + #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -26,21 +25,18 @@ #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. */ struct at91sam9_pin { - /** Target this pin is on. */ - struct target *target; - /** Address of the PIO controller. */ uint32_t pioc; @@ -52,9 +48,6 @@ struct at91sam9_pin { * Private data for the controller that is stored in the NAND device structure. */ struct at91sam9_nand { - /** Target the NAND is attached to. */ - struct target *target; - /** Address of the ECC controller for NAND. */ uint32_t ecc; @@ -101,12 +94,10 @@ static int at91sam9_halted(struct target *target, const char *label) */ static int at91sam9_init(struct nand_device *nand) { - struct at91sam9_nand *info = nand->controller_priv; - struct target *target = info->target; + struct target *target = nand->target; - if (!at91sam9_halted(target, "init")) { + if (!at91sam9_halted(target, "init")) return ERROR_NAND_OPERATION_FAILED; - } return ERROR_OK; } @@ -114,27 +105,29 @@ static int at91sam9_init(struct nand_device *nand) /** * Enable NAND device attached to a controller. * - * @param info NAND controller information for controlling NAND device. + * @param nand NAND controller information for controlling NAND device. * @return Success or failure of the enabling. */ -static int at91sam9_enable(struct at91sam9_nand *info) +static int at91sam9_enable(struct nand_device *nand) { - struct target *target = info->target; + struct at91sam9_nand *info = nand->controller_priv; + struct target *target = nand->target; - return target_write_u32(target, info->ce.pioc + AT91C_PIOx_CODR, 1 << info->ce.num); + return target_write_u32(target, info->ce.pioc + AT91C_PIOX_CODR, 1 << info->ce.num); } /** * Disable NAND device attached to a controller. * - * @param info NAND controller information for controlling NAND device. + * @param nand NAND controller information for controlling NAND device. * @return Success or failure of the disabling. */ -static int at91sam9_disable(struct at91sam9_nand *info) +static int at91sam9_disable(struct nand_device *nand) { - struct target *target = info->target; + struct at91sam9_nand *info = nand->controller_priv; + struct target *target = nand->target; - return target_write_u32(target, info->ce.pioc + AT91C_PIOx_SODR, 1 << info->ce.num); + return target_write_u32(target, info->ce.pioc + AT91C_PIOX_SODR, 1 << info->ce.num); } /** @@ -147,13 +140,12 @@ static int at91sam9_disable(struct at91sam9_nand *info) static int at91sam9_command(struct nand_device *nand, uint8_t command) { struct at91sam9_nand *info = nand->controller_priv; - struct target *target = info->target; + struct target *target = nand->target; - if (!at91sam9_halted(target, "command")) { + if (!at91sam9_halted(target, "command")) return ERROR_NAND_OPERATION_FAILED; - } - at91sam9_enable(info); + at91sam9_enable(nand); return target_write_u8(target, info->cmd, command); } @@ -166,13 +158,10 @@ static int at91sam9_command(struct nand_device *nand, uint8_t command) */ static int at91sam9_reset(struct nand_device *nand) { - struct at91sam9_nand *info = nand->controller_priv; - - if (!at91sam9_halted(info->target, "reset")) { + if (!at91sam9_halted(nand->target, "reset")) return ERROR_NAND_OPERATION_FAILED; - } - return at91sam9_disable(info); + return at91sam9_disable(nand); } /** @@ -185,11 +174,10 @@ static int at91sam9_reset(struct nand_device *nand) static int at91sam9_address(struct nand_device *nand, uint8_t address) { struct at91sam9_nand *info = nand->controller_priv; - struct target *target = info->target; + struct target *target = nand->target; - if (!at91sam9_halted(info->target, "address")) { + if (!at91sam9_halted(nand->target, "address")) return ERROR_NAND_OPERATION_FAILED; - } return target_write_u8(target, info->addr, address); } @@ -205,11 +193,10 @@ static int at91sam9_address(struct nand_device *nand, uint8_t address) static int at91sam9_read_data(struct nand_device *nand, void *data) { struct at91sam9_nand *info = nand->controller_priv; - struct target *target = info->target; + struct target *target = nand->target; - if (!at91sam9_halted(info->target, "read data")) { + if (!at91sam9_halted(nand->target, "read data")) return ERROR_NAND_OPERATION_FAILED; - } return target_read_u8(target, info->data, data); } @@ -225,11 +212,10 @@ static int at91sam9_read_data(struct nand_device *nand, void *data) static int at91sam9_write_data(struct nand_device *nand, uint16_t data) { struct at91sam9_nand *info = nand->controller_priv; - struct target *target = info->target; + 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); } @@ -244,19 +230,17 @@ static int at91sam9_write_data(struct nand_device *nand, uint16_t data) static int at91sam9_nand_ready(struct nand_device *nand, int timeout) { struct at91sam9_nand *info = nand->controller_priv; - struct target *target = info->target; + 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); + 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); @@ -279,9 +263,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(info->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); @@ -304,9 +287,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(info->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); @@ -328,8 +310,8 @@ static int at91sam9_ecc_init(struct target *target, struct at91sam9_nand *info) return ERROR_NAND_OPERATION_FAILED; } - // reset ECC parity registers - return target_write_u32(target, info->ecc + AT91C_ECCx_CR, 1); + /* reset ECC parity registers */ + return target_write_u32(target, info->ecc + AT91C_ECCX_CR, 1); } /** @@ -342,19 +324,19 @@ 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) { LOG_ERROR("Unable to allocate space for OOB"); + return NULL; } memset(oob, 0xFF, *size); @@ -377,64 +359,61 @@ 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; - struct target *target = info->target; + struct target *target = nand->target; uint8_t *oob_data; uint32_t status; retval = at91sam9_ecc_init(target, info); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) return retval; - } retval = nand_page_command(nand, page, NAND_CMD_READ0, !data); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) return retval; - } if (data) { retval = nand_read_data_page(nand, data, data_size); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) return retval; - } } oob_data = at91sam9_oob_init(nand, oob, &oob_size); retval = nand_read_data_page(nand, oob_data, oob_size); if (ERROR_OK == retval && data) { - target_read_u32(target, info->ecc + AT91C_ECCx_SR, &status); + 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); } @@ -455,27 +434,25 @@ 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 = info->target; + struct target *target = nand->target; int retval; uint8_t *oob_data = oob; uint32_t parity, nparity; retval = at91sam9_ecc_init(target, info); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) return retval; - } retval = nand_page_command(nand, page, NAND_CMD_SEQIN, !data); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) return retval; - } if (data) { retval = nand_write_data_page(nand, data, data_size); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("Unable to write data to NAND device"); return retval; } @@ -484,9 +461,9 @@ 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 - target_read_u32(target, info->ecc + AT91C_ECCx_PR, &parity); - target_read_u32(target, info->ecc + AT91C_ECCx_NPR, &nparity); + /* 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); oob_data[0] = (uint8_t) parity; oob_data[1] = (uint8_t) (parity >> 8); @@ -496,11 +473,10 @@ 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) { + if (retval != ERROR_OK) { LOG_ERROR("Unable to write OOB data to NAND"); return retval; } @@ -517,23 +493,16 @@ static int at91sam9_write_page(struct nand_device *nand, uint32_t page, */ NAND_DEVICE_COMMAND_HANDLER(at91sam9_nand_device_command) { - struct target *target = NULL; unsigned long chip = 0, ecc = 0; struct at91sam9_nand *info = NULL; - LOG_DEBUG("AT91SAM9 NAND Device Command\n"); + LOG_DEBUG("AT91SAM9 NAND Device Command"); if (CMD_ARGC < 3 || CMD_ARGC > 4) { LOG_ERROR("parameters: %s target chip_addr", CMD_ARGV[0]); return ERROR_NAND_OPERATION_FAILED; } - target = get_target(CMD_ARGV[1]); - if (!target) { - LOG_ERROR("invalid target: %s", CMD_ARGV[1]); - return ERROR_NAND_OPERATION_FAILED; - } - COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[2], chip); if (chip == 0) { LOG_ERROR("invalid NAND chip address: %s", CMD_ARGV[2]); @@ -554,14 +523,13 @@ NAND_DEVICE_COMMAND_HANDLER(at91sam9_nand_device_command) return ERROR_NAND_OPERATION_FAILED; } - info->target = target; info->data = chip; info->cmd = chip | (1 << 22); info->addr = chip | (1 << 21); info->ecc = ecc; nand->controller_priv = info; - info->io.target = target; + info->io.target = nand->target; info->io.data = info->data; info->io.op = ARM_NAND_NONE; @@ -579,14 +547,14 @@ COMMAND_HANDLER(handle_at91sam9_cle_command) unsigned num, address_line; if (CMD_ARGC != 2) { - command_print(CMD_CTX, "incorrect number of arguments for 'at91sam9 cle' command"); + command_print(CMD, "incorrect number of arguments for 'at91sam9 cle' command"); return ERROR_OK; } COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], num); nand = get_nand_device_by_num(num); if (!nand) { - command_print(CMD_CTX, "invalid nand device number: %s", CMD_ARGV[0]); + command_print(CMD, "invalid nand device number: %s", CMD_ARGV[0]); return ERROR_OK; } @@ -608,14 +576,13 @@ 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); if (!nand) { - command_print(CMD_CTX, "invalid nand device number: %s", CMD_ARGV[0]); + command_print(CMD, "invalid nand device number: %s", CMD_ARGV[0]); return ERROR_COMMAND_ARGUMENT_INVALID; } @@ -637,14 +604,13 @@ 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); if (!nand) { - command_print(CMD_CTX, "invalid nand device number: %s", CMD_ARGV[0]); + command_print(CMD, "invalid nand device number: %s", CMD_ARGV[0]); return ERROR_COMMAND_ARGUMENT_INVALID; } @@ -669,14 +635,13 @@ 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); if (!nand) { - command_print(CMD_CTX, "invalid nand device number: %s", CMD_ARGV[0]); + command_print(CMD, "invalid nand device number: %s", CMD_ARGV[0]); return ERROR_COMMAND_ARGUMENT_INVALID; } @@ -730,6 +695,7 @@ static const struct command_registration at91sam9_command_handler[] = { .name = "at91sam9", .mode = COMMAND_ANY, .help = "AT91SAM9 NAND flash controller commands", + .usage = "", .chain = at91sam9_sub_command_handlers, }, COMMAND_REGISTRATION_DONE