summaryrefslogtreecommitdiff
path: root/src/flash/davinci_nand.c
diff options
context:
space:
mode:
authorZachary T Welch <zw@superlucidity.net>2009-12-01 22:37:11 -0800
committerZachary T Welch <zw@superlucidity.net>2009-12-02 23:27:09 -0800
commite1ec02bb055fa356b058dddc0a15710e0fdc9870 (patch)
tree62110f0c0262314d7d0d9312e46f3113441a48ea /src/flash/davinci_nand.c
parentd5e4e23f9a5b1074cd298d5386e638a9fa78b1ad (diff)
downloadopenocd+libswd-e1ec02bb055fa356b058dddc0a15710e0fdc9870.tar.gz
openocd+libswd-e1ec02bb055fa356b058dddc0a15710e0fdc9870.tar.bz2
openocd+libswd-e1ec02bb055fa356b058dddc0a15710e0fdc9870.tar.xz
openocd+libswd-e1ec02bb055fa356b058dddc0a15710e0fdc9870.zip
move nand drivers to src/flash/nand/
Moves NAND drivers to src/flash/nand/. Adds src/flash/nand/Makefile.am. Builds libocdflashnand.la.
Diffstat (limited to 'src/flash/davinci_nand.c')
-rw-r--r--src/flash/davinci_nand.c756
1 files changed, 0 insertions, 756 deletions
diff --git a/src/flash/davinci_nand.c b/src/flash/davinci_nand.c
deleted file mode 100644
index 72cd378a..00000000
--- a/src/flash/davinci_nand.c
+++ /dev/null
@@ -1,756 +0,0 @@
-/***************************************************************************
- * Copyright (C) 2009 by David Brownell *
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * 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. *
- ***************************************************************************/
-
-/*
- * DaVinci family NAND controller support for OpenOCD.
- *
- * This driver uses hardware ECC (1-bit or 4-bit) unless
- * the chip is accessed in "raw" mode.
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "arm_nandio.h"
-
-
-enum ecc {
- HWECC1, /* all controllers support 1-bit ECC */
- HWECC4, /* newer chips also have 4-bit ECC hardware */
- HWECC4_INFIX, /* avoid this layout, except maybe for boot code */
-};
-
-struct davinci_nand {
- struct target *target;
-
- uint8_t chipsel; /* chipselect 0..3 == CS2..CS5 */
- uint8_t eccmode;
-
- /* Async EMIF controller base */
- uint32_t aemif;
-
- /* NAND chip addresses */
- uint32_t data; /* without CLE or ALE */
- 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 *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);
-};
-
-#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)
-{
- if (target->state == TARGET_HALTED)
- return true;
-
- LOG_ERROR("Target must be halted to use NAND controller (%s)", label);
- return false;
-}
-
-static int davinci_init(struct nand_device *nand)
-{
- struct davinci_nand *info = nand->controller_priv;
- struct target *target = info->target;
- uint32_t nandfcr;
-
- if (!halted(target, "init"))
- return ERROR_NAND_OPERATION_FAILED;
-
- /* We require something else to have configured AEMIF to talk
- * to NAND chip in this range (including timings and width).
- */
- target_read_u32(target, info->aemif + NANDFCR, &nandfcr);
- if (!(nandfcr & (1 << info->chipsel))) {
- LOG_ERROR("chip address %08" PRIx32 " not NAND-enabled?", info->data);
- return ERROR_NAND_OPERATION_FAILED;
- }
-
- /* REVISIT verify: AxCR must be in 8-bit mode, since that's all we
- * tested. 16 bit support should work too; but not with 4-bit ECC.
- */
-
- return ERROR_OK;
-}
-
-static int davinci_reset(struct nand_device *nand)
-{
- return ERROR_OK;
-}
-
-static int davinci_nand_ready(struct nand_device *nand, int timeout)
-{
- struct davinci_nand *info = nand->controller_priv;
- struct target *target = info->target;
- uint32_t nandfsr;
-
- /* NOTE: return code is zero/error, else success; not ERROR_* */
-
- if (!halted(target, "ready"))
- return 0;
-
- do {
- target_read_u32(target, info->aemif + NANDFSR, &nandfsr);
-
- if (nandfsr & 0x01)
- return 1;
-
- alive_sleep(1);
- } while (timeout-- > 0);
-
- return 0;
-}
-
-static int davinci_command(struct nand_device *nand, uint8_t command)
-{
- struct davinci_nand *info = nand->controller_priv;
- struct target *target = info->target;
-
- if (!halted(target, "command"))
- return ERROR_NAND_OPERATION_FAILED;
-
- target_write_u8(target, info->cmd, command);
- return ERROR_OK;
-}
-
-static int davinci_address(struct nand_device *nand, uint8_t address)
-{
- struct davinci_nand *info = nand->controller_priv;
- struct target *target = info->target;
-
- if (!halted(target, "address"))
- return ERROR_NAND_OPERATION_FAILED;
-
- target_write_u8(target, info->addr, address);
- return ERROR_OK;
-}
-
-static int davinci_write_data(struct nand_device *nand, uint16_t data)
-{
- struct davinci_nand *info = nand->controller_priv;
- struct target *target = info->target;
-
- if (!halted(target, "write_data"))
- return ERROR_NAND_OPERATION_FAILED;
-
- target_write_u8(target, info->data, data);
- return ERROR_OK;
-}
-
-static int davinci_read_data(struct nand_device *nand, void *data)
-{
- struct davinci_nand *info = nand->controller_priv;
- struct target *target = info->target;
-
- if (!halted(target, "read_data"))
- return ERROR_NAND_OPERATION_FAILED;
-
- target_read_u8(target, info->data, data);
- return ERROR_OK;
-}
-
-/* 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)
-{
- struct davinci_nand *info = nand->controller_priv;
- struct target *target = info->target;
- uint32_t nfdata = info->data;
- uint32_t tmp;
-
- if (!halted(target, "read_block"))
- return ERROR_NAND_OPERATION_FAILED;
-
- while (data_size >= 4) {
- target_read_u32(target, nfdata, &tmp);
-
- data[0] = tmp;
- data[1] = tmp >> 8;
- data[2] = tmp >> 16;
- data[3] = tmp >> 24;
-
- data_size -= 4;
- data += 4;
- }
-
- while (data_size > 0) {
- target_read_u8(target, nfdata, data);
-
- data_size -= 1;
- data += 1;
- }
-
- return ERROR_OK;
-}
-
-static int davinci_write_block_data(struct nand_device *nand,
- uint8_t *data, int data_size)
-{
- struct davinci_nand *info = nand->controller_priv;
- 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);
-
- data_size -= 4;
- data += 4;
- }
-
- while (data_size > 0) {
- target_write_u8(target, nfdata, *data);
-
- data_size -= 1;
- data += 1;
- }
-
- return ERROR_OK;
-}
-
-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;
- uint8_t *ooballoc = NULL;
- int status;
-
- if (!nand->device)
- return ERROR_NAND_DEVICE_NOT_PROBED;
- if (!halted(info->target, "write_page"))
- return ERROR_NAND_OPERATION_FAILED;
-
- /* Always write both data and OOB ... we are not "raw" I/O! */
- if (!data) {
- LOG_ERROR("Missing NAND data; try 'nand raw_access enable'\n");
- return ERROR_NAND_OPERATION_FAILED;
- }
-
- /* 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;
- }
- if (!oob) {
- ooballoc = malloc(oob_size);
- if (!ooballoc)
- return ERROR_NAND_OPERATION_FAILED;
- oob = ooballoc;
- 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 *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;
-
- if (!nand->device)
- return ERROR_NAND_DEVICE_NOT_PROBED;
- if (!halted(info->target, "read_page"))
- return ERROR_NAND_OPERATION_FAILED;
-
- return info->read_page(nand, page, data, data_size, oob, oob_size);
-}
-
-static void davinci_write_pagecmd(struct nand_device *nand, uint8_t cmd, uint32_t page)
-{
- struct davinci_nand *info = nand->controller_priv;
- 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->cmd, cmd);
-
- /* column address (beginning-of-page) */
- target_write_u8(target, info->addr, 0);
- if (nand->page_size > 512)
- target_write_u8(target, info->addr, 0);
-
- /* page address */
- target_write_u8(target, info->addr, page);
- target_write_u8(target, info->addr, page >> 8);
- if (page3)
- target_write_u8(target, info->addr, page >> 16);
- if (page3 == 2)
- target_write_u8(target, info->addr, page >> 24);
-}
-
-static int davinci_writepage_tail(struct nand_device *nand,
- uint8_t *oob, uint32_t oob_size)
-{
- struct davinci_nand *info = nand->controller_priv;
- struct target *target = info->target;
- uint8_t status;
-
- if (oob_size)
- davinci_write_block_data(nand, oob, oob_size);
-
- /* non-cachemode page program */
- target_write_u8(target, info->cmd, NAND_CMD_PAGEPROG);
-
- if (!davinci_nand_ready(nand, 100))
- return ERROR_NAND_OPERATION_TIMEOUT;
-
- if (nand_read_status(nand, &status) != ERROR_OK) {
- LOG_ERROR("couldn't read status");
- return ERROR_NAND_OPERATION_FAILED;
- }
-
- if (status & NAND_STATUS_FAIL) {
- LOG_ERROR("write operation failed, status: 0x%02x", status);
- return ERROR_NAND_OPERATION_FAILED;
- }
-
- return ERROR_OK;
-}
-
-/*
- * 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)
-{
- unsigned oob_offset;
- struct davinci_nand *info = nand->controller_priv;
- struct target *target = info->target;
- const uint32_t fcr_addr = info->aemif + NANDFCR;
- const uint32_t ecc1_addr = info->aemif + NANDFECC + (4 * info->chipsel);
- uint32_t fcr, ecc1;
-
- /* Write contiguous ECC bytes starting at specified offset.
- * NOTE: Linux reserves twice as many bytes as we need; and
- * 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;
- }
-
- davinci_write_pagecmd(nand, NAND_CMD_SEQIN, page);
-
- /* scrub any old ECC state */
- target_read_u32(target, ecc1_addr, &ecc1);
-
- target_read_u32(target, fcr_addr, &fcr);
- fcr |= 1 << (8 + info->chipsel);
-
- do {
- /* set "start csX 1bit ecc" bit */
- target_write_u32(target, fcr_addr, fcr);
-
- /* write 512 bytes */
- davinci_write_block_data(nand, data, 512);
- data += 512;
- data_size -= 512;
-
- /* read the ecc, pack to 3 bytes, and invert so the ecc
- * in an erased block is correct
- */
- target_read_u32(target, ecc1_addr, &ecc1);
- ecc1 = (ecc1 & 0x0fff) | ((ecc1 & 0x0fff0000) >> 4);
- ecc1 = ~ecc1;
-
- /* save correct ECC code into oob data */
- oob[oob_offset++] = (uint8_t)(ecc1);
- oob[oob_offset++] = (uint8_t)(ecc1 >> 8);
- oob[oob_offset++] = (uint8_t)(ecc1 >> 16);
-
- } while (data_size);
-
- /* write OOB into spare area */
- return davinci_writepage_tail(nand, oob, oob_size);
-}
-
-/*
- * Preferred "new style" ECC layout for use with 4-bit ECC. This somewhat
- * slows down large page reads done with error correction (since the OOB
- * 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 *nand, uint32_t page,
- 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 */
- 6, 7, /* 8..12 for BBT or JFFS2 */ 13, 14, 15,
- };
- static const uint8_t ecc2048[] = {
- 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
- 34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
- 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
- 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,
- 108, 109, 110, 111, 112, 113, 114, 115, 116, 117,
- 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
- };
-
- struct davinci_nand *info = nand->controller_priv;
- const uint8_t *l;
- 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;
-
- /* Use the same ECC layout Linux uses. For small page chips
- * it's a bit cramped.
- *
- * NOTE: at this writing, 4KB pages have issues in Linux
- * because they need more than 64 bytes of ECC data, which
- * 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;
- }
-
- davinci_write_pagecmd(nand, NAND_CMD_SEQIN, page);
-
- /* scrub any old ECC state */
- target_read_u32(target, info->aemif + NANDERRVAL, &ecc4);
-
- target_read_u32(target, fcr_addr, &fcr);
- fcr &= ~(0x03 << 4);
- fcr |= (1 << 12) | (info->chipsel << 4);
-
- do {
- uint32_t raw_ecc[4], *p;
- int i;
-
- /* start 4bit ecc on csX */
- target_write_u32(target, fcr_addr, fcr);
-
- /* write 512 bytes */
- davinci_write_block_data(nand, data, 512);
- data += 512;
- data_size -= 512;
-
- /* read the ecc, then save it into 10 bytes in the oob */
- for (i = 0; i < 4; i++) {
- target_read_u32(target, ecc4_addr + 4 * i, &raw_ecc[i]);
- raw_ecc[i] &= 0x03ff03ff;
- }
- for (i = 0, p = raw_ecc; i < 2; i++, p += 2) {
- 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;
- }
-
- } while (data_size);
-
- /* write OOB into spare area */
- return davinci_writepage_tail(nand, oob, oob_size);
-}
-
-/*
- * "Infix" OOB ... like Linux ECC_HW_SYNDROME. Avoided because it trashes
- * manufacturer bad block markers, except on small page chips. Once you
- * write to a page using this scheme, you need specialized code to update
- * it (code which ignores now-invalid bad block markers).
- *
- * This is needed *only* to support older firmware. Older ROM Boot Loaders
- * need it to read their second stage loader (UBL) into SRAM, but from then
- * on the whole system can use the cleaner non-infix layouts. Systems with
- * 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 *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;
- 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;
-
- davinci_write_pagecmd(nand, NAND_CMD_SEQIN, page);
-
- /* scrub any old ECC state */
- target_read_u32(target, info->aemif + NANDERRVAL, &ecc4);
-
- target_read_u32(target, fcr_addr, &fcr);
- fcr &= ~(0x03 << 4);
- fcr |= (1 << 12) | (info->chipsel << 4);
-
- do {
- uint32_t raw_ecc[4], *p;
- uint8_t *l;
- int i;
-
- /* start 4bit ecc on csX */
- target_write_u32(target, fcr_addr, fcr);
-
- /* write 512 bytes */
- davinci_write_block_data(nand, data, 512);
- data += 512;
- data_size -= 512;
-
- /* read the ecc */
- for (i = 0; i < 4; i++) {
- target_read_u32(target, ecc4_addr + 4 * i, &raw_ecc[i]);
- raw_ecc[i] &= 0x03ff03ff;
- }
-
- /* 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] >> 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;
- }
-
- /* write this "out-of-band" data -- infix */
- davinci_write_block_data(nand, oob, 16);
- oob += 16;
- oob_size -= 16;
-
- } while (data_size);
-
- /* the last data and OOB writes included the spare area */
- return davinci_writepage_tail(nand, NULL, 0);
-}
-
-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);
-
- /* large page devices need a start command */
- if (nand->page_size > 512)
- davinci_command(nand, NAND_CMD_READSTART);
-
- if (!davinci_nand_ready(nand, 100))
- return ERROR_NAND_OPERATION_TIMEOUT;
-
- /* NOTE: not bothering to compute and use ECC data for now */
-
- do {
- /* write 512 bytes */
- davinci_read_block_data(nand, data, 512);
- data += 512;
- data_size -= 512;
-
- /* read this "out-of-band" data -- infix */
- davinci_read_block_data(nand, oob, 16);
- oob += 16;
- oob_size -= 16;
- } while (data_size);
-
- return ERROR_OK;
-}
-
-NAND_DEVICE_COMMAND_HANDLER(davinci_nand_device_command)
-{
- struct davinci_nand *info;
- struct target *target;
- unsigned long chip, aemif;
- enum ecc eccmode;
- int chipsel;
-
- /* arguments:
- * - "davinci"
- * - target
- * - nand chip address
- * - ecc mode
- * - aemif address
- * Plus someday, optionally, ALE and CLE masks.
- */
- if (CMD_ARGC < 5) {
- LOG_ERROR("parameters: %s target "
- "chip_addr hwecc_mode aemif_addr",
- CMD_ARGV[0]);
- goto fail;
- }
-
- target = get_target(CMD_ARGV[1]);
- if (!target) {
- LOG_ERROR("invalid target %s", CMD_ARGV[1]);
- goto fail;
- }
-
- COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[2], chip);
- if (chip == 0) {
- LOG_ERROR("Invalid NAND chip address %s", CMD_ARGV[2]);
- goto fail;
- }
-
- if (strcmp(CMD_ARGV[3], "hwecc1") == 0)
- eccmode = HWECC1;
- else if (strcmp(CMD_ARGV[3], "hwecc4") == 0)
- eccmode = HWECC4;
- else if (strcmp(CMD_ARGV[3], "hwecc4_infix") == 0)
- eccmode = HWECC4_INFIX;
- else {
- LOG_ERROR("Invalid ecc mode %s", CMD_ARGV[3]);
- goto fail;
- }
-
- COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[4], aemif);
- if (aemif == 0) {
- LOG_ERROR("Invalid AEMIF controller address %s", CMD_ARGV[4]);
- goto fail;
- }
-
- /* REVISIT what we'd *like* to do is look up valid ranges using
- * target-specific declarations, and not even need to pass the
- * AEMIF controller address.
- */
- if (aemif == 0x01e00000 /* dm6446, dm357 */
- || aemif == 0x01e10000 /* dm335, dm355 */
- || aemif == 0x01d10000 /* dm365 */
- ) {
- if (chip < 0x02000000 || chip >= 0x0a000000) {
- LOG_ERROR("NAND address %08lx out of range?", chip);
- goto fail;
- }
- chipsel = (chip - 0x02000000) >> 25;
- } else {
- LOG_ERROR("unrecognized AEMIF controller address %08lx", aemif);
- goto fail;
- }
-
- info = calloc(1, sizeof *info);
- if (info == NULL)
- goto fail;
-
- info->target = target;
- info->eccmode = eccmode;
- info->chipsel = chipsel;
- info->aemif = aemif;
- info->data = chip;
- info->cmd = chip | 0x10;
- info->addr = chip | 0x08;
-
- 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.
- */
- 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;
- }
-
- return ERROR_OK;
-
-fail:
- return ERROR_NAND_OPERATION_FAILED;
-}
-
-struct nand_flash_controller davinci_nand_controller = {
- .name = "davinci",
- .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,
-};