#include "config.h"
#endif
-#include "nand.h"
+#include "arm_nandio.h"
enum ecc {
};
struct davinci_nand {
- target_t *target;
+ struct target *target;
uint8_t chipsel; /* chipselect 0..3 == CS2..CS5 */
uint8_t eccmode;
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,
+ 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 (*write_page)(struct nand_device_s *nand, uint32_t page,
+ int (*write_page)(struct nand_device *nand, uint32_t page,
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size);
};
#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(target_t *target, const char *label)
+static int halted(struct target *target, const char *label)
{
if (target->state == TARGET_HALTED)
return true;
return false;
}
-static int davinci_register_commands(struct command_context_s *cmd_ctx)
+static int davinci_register_commands(struct command_context *cmd_ctx)
{
return ERROR_OK;
}
-static int davinci_init(struct nand_device_s *nand)
+static int davinci_init(struct nand_device *nand)
{
struct davinci_nand *info = nand->controller_priv;
- target_t *target = info->target;
+ struct target *target = info->target;
uint32_t nandfcr;
if (!halted(target, "init"))
return ERROR_OK;
}
-static int davinci_reset(struct nand_device_s *nand)
+static int davinci_reset(struct nand_device *nand)
{
return ERROR_OK;
}
-static int davinci_nand_ready(struct nand_device_s *nand, int timeout)
+static int davinci_nand_ready(struct nand_device *nand, int timeout)
{
struct davinci_nand *info = nand->controller_priv;
- target_t *target = info->target;
+ struct target *target = info->target;
uint32_t nandfsr;
/* NOTE: return code is zero/error, else success; not ERROR_* */
return 0;
}
-static int davinci_command(struct nand_device_s *nand, uint8_t command)
+static int davinci_command(struct nand_device *nand, uint8_t command)
{
struct davinci_nand *info = nand->controller_priv;
- target_t *target = info->target;
+ struct target *target = info->target;
if (!halted(target, "command"))
return ERROR_NAND_OPERATION_FAILED;
return ERROR_OK;
}
-static int davinci_address(struct nand_device_s *nand, uint8_t address)
+static int davinci_address(struct nand_device *nand, uint8_t address)
{
struct davinci_nand *info = nand->controller_priv;
- target_t *target = info->target;
+ struct target *target = info->target;
if (!halted(target, "address"))
return ERROR_NAND_OPERATION_FAILED;
return ERROR_OK;
}
-static int davinci_write_data(struct nand_device_s *nand, uint16_t data)
+static int davinci_write_data(struct nand_device *nand, uint16_t data)
{
struct davinci_nand *info = nand->controller_priv;
- target_t *target = info->target;
+ struct target *target = info->target;
if (!halted(target, "write_data"))
return ERROR_NAND_OPERATION_FAILED;
return ERROR_OK;
}
-static int davinci_read_data(struct nand_device_s *nand, void *data)
+static int davinci_read_data(struct nand_device *nand, void *data)
{
struct davinci_nand *info = nand->controller_priv;
- target_t *target = info->target;
+ struct target *target = info->target;
if (!halted(target, "read_data"))
return ERROR_NAND_OPERATION_FAILED;
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,
+static int davinci_read_block_data(struct nand_device *nand,
uint8_t *data, int data_size)
{
struct davinci_nand *info = nand->controller_priv;
- target_t *target = info->target;
+ struct target *target = info->target;
uint32_t nfdata = info->data;
uint32_t tmp;
return ERROR_OK;
}
-static int davinci_write_block_data(struct nand_device_s *nand,
+static int davinci_write_block_data(struct nand_device *nand,
uint8_t *data, int data_size)
{
struct davinci_nand *info = nand->controller_priv;
- target_t *target = info->target;
+ struct target *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);
return ERROR_OK;
}
-static int davinci_write_page(struct nand_device_s *nand, uint32_t page,
+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)
{
struct davinci_nand *info = nand->controller_priv;
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;
}
-static int davinci_read_page(struct nand_device_s *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)
{
struct davinci_nand *info = nand->controller_priv;
return info->read_page(nand, page, data, data_size, oob, oob_size);
}
-static void davinci_write_pagecmd(struct nand_device_s *nand, uint8_t cmd, uint32_t page)
+static void davinci_write_pagecmd(struct nand_device *nand, uint8_t cmd, uint32_t page)
{
struct davinci_nand *info = nand->controller_priv;
- target_t *target = info->target;
+ struct target *target = info->target;
int page3 = nand->address_cycles - (nand->page_size == 512);
/* write command ({page,otp}x{read,program} */
target_write_u8(target, info->addr, page >> 24);
}
-static int davinci_writepage_tail(struct nand_device_s *nand,
+static int davinci_writepage_tail(struct nand_device *nand,
uint8_t *oob, uint32_t oob_size)
{
struct davinci_nand *info = nand->controller_priv;
- target_t *target = info->target;
+ struct target *target = info->target;
uint8_t status;
if (oob_size)
/*
* All DaVinci family chips support 1-bit ECC on a per-chipselect basis.
*/
-static int davinci_write_page_ecc1(struct nand_device_s *nand, uint32_t page,
+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)
{
unsigned oob_offset;
struct davinci_nand *info = nand->controller_priv;
- target_t *target = info->target;
+ struct target *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.
* is read first, so its ECC data can be used incrementally), but the
* manufacturer bad block markers are safe. Contrast: old "infix" style.
*/
-static int davinci_write_page_ecc4(struct nand_device_s *nand, uint32_t page,
+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)
{
static const uint8_t ecc512[] = {
struct davinci_nand *info = nand->controller_priv;
const uint8_t *l;
- target_t *target = info->target;
+ struct target *target = info->target;
const uint32_t fcr_addr = info->aemif + NANDFCR;
const uint32_t ecc4_addr = info->aemif + NAND4BITECC;
uint32_t fcr, ecc4;
* older second stage loaders (ABL/U-Boot, etc) or other system software
* (MVL 4.x/5.x kernels, filesystems, etc) may need it more generally.
*/
-static int davinci_write_page_ecc4infix(struct nand_device_s *nand, uint32_t page,
+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)
{
struct davinci_nand *info = nand->controller_priv;
- target_t *target = info->target;
+ struct target *target = info->target;
const uint32_t fcr_addr = info->aemif + NANDFCR;
const uint32_t ecc4_addr = info->aemif + NAND4BITECC;
uint32_t fcr, ecc4;
return davinci_writepage_tail(nand, NULL, 0);
}
-static int davinci_read_page_ecc4infix(struct nand_device_s *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)
{
davinci_write_pagecmd(nand, NAND_CMD_READ0, 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;
+ struct target *target;
unsigned long chip, aemif;
enum ecc eccmode;
int chipsel;
- char *ep;
/* arguments:
* - "davinci"
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;
}
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;
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.
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,