X-Git-Url: https://review.openocd.org/gitweb?a=blobdiff_plain;f=src%2Fflash%2Fdavinci_nand.c;h=d4c161975b319f03e0b4bc816313f3fe62f50112;hb=9059f9f28e4d88c9608ef92723bbd493e106ba67;hp=7ccd080f9092ecb09a1a82d293625ac8e0f3b885;hpb=dc575dc5bf8cb597a0e9a47794744ae6b1928087;p=openocd.git diff --git a/src/flash/davinci_nand.c b/src/flash/davinci_nand.c index 7ccd080f90..d4c161975b 100644 --- a/src/flash/davinci_nand.c +++ b/src/flash/davinci_nand.c @@ -28,7 +28,7 @@ #include "config.h" #endif -#include "nand.h" +#include "arm_nandio.h" enum ecc { @@ -51,6 +51,9 @@ struct davinci_nand { uint32_t cmd; /* with CLE */ uint32_t addr; /* with ALE */ + /* write acceleration */ + struct arm_nand_data io; + /* page i/o for the relevant flavor of hardware ECC */ int (*read_page)(struct nand_device_s *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size); @@ -181,7 +184,7 @@ static int davinci_read_data(struct nand_device_s *nand, void *data) return ERROR_OK; } -/* REVISIT a bit of native code should let block I/O be MUCH faster */ +/* REVISIT a bit of native code should let block reads be MUCH faster */ static int davinci_read_block_data(struct nand_device_s *nand, uint8_t *data, int data_size) @@ -223,10 +226,17 @@ static int davinci_write_block_data(struct nand_device_s *nand, target_t *target = info->target; uint32_t nfdata = info->data; uint32_t tmp; + int status; if (!halted(target, "write_block")) return ERROR_NAND_OPERATION_FAILED; + /* try the fast way first */ + status = arm_nandwrite(&info->io, data, data_size); + if (status != ERROR_NAND_NO_BUFFER) + return status; + + /* else do it slowly */ while (data_size >= 4) { tmp = le_to_h_u32(data); target_write_u32(target, nfdata, tmp); @@ -285,6 +295,12 @@ static int davinci_write_page(struct nand_device_s *nand, uint32_t page, memset(oob, 0x0ff, oob_size); } + /* REVISIT avoid wasting SRAM: unless nand->use_raw is set, + * use 512 byte chunks. Read side support will often want + * to include oob_size ... + */ + info->io.chunk_size = nand->page_size; + status = info->write_page(nand, page, data, data_size, oob, oob_size); free(ooballoc); return status; @@ -365,7 +381,7 @@ static int davinci_write_page_ecc1(struct nand_device_s *nand, uint32_t page, struct davinci_nand *info = nand->controller_priv; target_t *target = info->target; const uint32_t fcr_addr = info->aemif + NANDFCR; - const uint32_t ecc1_addr = info->aemif + NANDFECC + info->chipsel; + const uint32_t ecc1_addr = info->aemif + NANDFECC + (4 * info->chipsel); uint32_t fcr, ecc1; /* Write contiguous ECC bytes starting at specified offset. @@ -613,16 +629,13 @@ static int davinci_read_page_ecc4infix(struct nand_device_s *nand, uint32_t page return ERROR_OK; } -static int davinci_nand_device_command(struct command_context_s *cmd_ctx, - char *cmd, char **argv, int argc, - struct nand_device_s *nand) +NAND_DEVICE_COMMAND_HANDLER(davinci_nand_device_command) { struct davinci_nand *info; target_t *target; unsigned long chip, aemif; enum ecc eccmode; int chipsel; - char *ep; /* arguments: * - "davinci" @@ -635,36 +648,36 @@ static int davinci_nand_device_command(struct command_context_s *cmd_ctx, if (argc < 5) { LOG_ERROR("parameters: %s target " "chip_addr hwecc_mode aemif_addr", - argv[0]); + args[0]); goto fail; } - target = get_target(argv[1]); + target = get_target(args[1]); if (!target) { - LOG_ERROR("invalid target %s", argv[1]); + LOG_ERROR("invalid target %s", args[1]); goto fail; } - chip = strtoul(argv[2], &ep, 0); - if (*ep || chip == 0 || chip == ULONG_MAX) { - LOG_ERROR("Invalid NAND chip address %s", argv[2]); + COMMAND_PARSE_NUMBER(ulong, args[2], chip); + if (chip == 0) { + LOG_ERROR("Invalid NAND chip address %s", args[2]); goto fail; } - if (strcmp(argv[3], "hwecc1") == 0) + if (strcmp(args[3], "hwecc1") == 0) eccmode = HWECC1; - else if (strcmp(argv[3], "hwecc4") == 0) + else if (strcmp(args[3], "hwecc4") == 0) eccmode = HWECC4; - else if (strcmp(argv[3], "hwecc4_infix") == 0) + else if (strcmp(args[3], "hwecc4_infix") == 0) eccmode = HWECC4_INFIX; else { - LOG_ERROR("Invalid ecc mode %s", argv[3]); + LOG_ERROR("Invalid ecc mode %s", args[3]); goto fail; } - aemif = strtoul(argv[4], &ep, 0); - if (*ep || chip == 0 || chip == ULONG_MAX) { - LOG_ERROR("Invalid AEMIF controller address %s", argv[4]); + COMMAND_PARSE_NUMBER(ulong, args[4], aemif); + if (aemif == 0) { + LOG_ERROR("Invalid AEMIF controller address %s", args[4]); goto fail; } @@ -675,12 +688,12 @@ static int davinci_nand_device_command(struct command_context_s *cmd_ctx, if (aemif == 0x01e00000 /* dm6446, dm357 */ || aemif == 0x01e10000 /* dm335, dm355 */ || aemif == 0x01d10000 /* dm365 */ -) { - if (chip < 0x0200000 || chip >= 0x0a000000) { + ) { + if (chip < 0x02000000 || chip >= 0x0a000000) { LOG_ERROR("NAND address %08lx out of range?", chip); goto fail; } - chipsel = (chip - 0x02000000) >> 21; + chipsel = (chip - 0x02000000) >> 25; } else { LOG_ERROR("unrecognized AEMIF controller address %08lx", aemif); goto fail; @@ -700,6 +713,9 @@ static int davinci_nand_device_command(struct command_context_s *cmd_ctx, nand->controller_priv = info; + info->io.target = target; + info->io.data = info->data; + /* NOTE: for now we don't do any error correction on read. * Nothing else in OpenOCD currently corrects read errors, * and in any case it's *writing* that we care most about. @@ -728,7 +744,7 @@ fail: return ERROR_NAND_OPERATION_FAILED; } -nand_flash_controller_t davinci_nand_controller = { +struct nand_flash_controller davinci_nand_controller = { .name = "davinci", .nand_device_command = davinci_nand_device_command, .register_commands = davinci_register_commands,