#include "config.h"
#endif
-#include "nand.h"
+#include "arm_nandio.h"
enum ecc {
struct davinci_nand {
target_t *target;
- u8 chipsel; /* chipselect 0..3 == CS2..CS5 */
- u8 eccmode;
+ uint8_t chipsel; /* chipselect 0..3 == CS2..CS5 */
+ uint8_t eccmode;
/* Async EMIF controller base */
- u32 aemif;
+ uint32_t aemif;
/* NAND chip addresses */
- u32 data; /* without CLE or ALE */
- u32 cmd; /* with CLE */
- u32 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;
/* page i/o for the relevant flavor of hardware ECC */
- int (*read_page)(struct nand_device_s *nand, u32 page,
- u8 *data, u32 data_size, u8 *oob, u32 oob_size);
- int (*write_page)(struct nand_device_s *nand, u32 page,
- u8 *data, u32 data_size, u8 *oob, u32 oob_size);
+ 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);
+ int (*write_page)(struct nand_device_s *nand, uint32_t page,
+ uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size);
};
#define NANDFCR 0x60 /* flash control register */
{
struct davinci_nand *info = nand->controller_priv;
target_t *target = info->target;
- u32 nandfcr;
+ uint32_t nandfcr;
if (!halted(target, "init"))
return ERROR_NAND_OPERATION_FAILED;
*/
target_read_u32(target, info->aemif + NANDFCR, &nandfcr);
if (!(nandfcr & (1 << info->chipsel))) {
- LOG_ERROR("chip address %08x not NAND-enabled?", info->data);
+ LOG_ERROR("chip address %08" PRIx32 " not NAND-enabled?", info->data);
return ERROR_NAND_OPERATION_FAILED;
}
{
struct davinci_nand *info = nand->controller_priv;
target_t *target = info->target;
- u32 nandfsr;
+ uint32_t nandfsr;
/* NOTE: return code is zero/error, else success; not ERROR_* */
return 0;
}
-static int davinci_command(struct nand_device_s *nand, u8 command)
+static int davinci_command(struct nand_device_s *nand, uint8_t command)
{
struct davinci_nand *info = nand->controller_priv;
target_t *target = info->target;
return ERROR_OK;
}
-static int davinci_address(struct nand_device_s *nand, u8 address)
+static int davinci_address(struct nand_device_s *nand, uint8_t address)
{
struct davinci_nand *info = nand->controller_priv;
target_t *target = info->target;
return ERROR_OK;
}
-static int davinci_write_data(struct nand_device_s *nand, u16 data)
+static int davinci_write_data(struct nand_device_s *nand, uint16_t data)
{
struct davinci_nand *info = nand->controller_priv;
target_t *target = info->target;
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,
- u8 *data, int data_size)
+ uint8_t *data, int data_size)
{
struct davinci_nand *info = nand->controller_priv;
target_t *target = info->target;
- u32 nfdata = info->data;
- u32 tmp;
+ uint32_t nfdata = info->data;
+ uint32_t tmp;
if (!halted(target, "read_block"))
return ERROR_NAND_OPERATION_FAILED;
}
static int davinci_write_block_data(struct nand_device_s *nand,
- u8 *data, int data_size)
+ uint8_t *data, int data_size)
{
struct davinci_nand *info = nand->controller_priv;
target_t *target = info->target;
- u32 nfdata = info->data;
- u32 tmp;
+ 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, u32 page,
- u8 *data, u32 data_size, u8 *oob, u32 oob_size)
+static int davinci_write_page(struct nand_device_s *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;
- u8 *ooballoc = NULL;
+ uint8_t *ooballoc = NULL;
int status;
if (!nand->device)
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, u32 page,
- u8 *data, u32 data_size, u8 *oob, u32 oob_size)
+static int davinci_read_page(struct nand_device_s *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, u8 cmd, u32 page)
+static void davinci_write_pagecmd(struct nand_device_s *nand, uint8_t cmd, uint32_t page)
{
struct davinci_nand *info = nand->controller_priv;
target_t *target = info->target;
}
static int davinci_writepage_tail(struct nand_device_s *nand,
- u8 *oob, u32 oob_size)
+ uint8_t *oob, uint32_t oob_size)
{
struct davinci_nand *info = nand->controller_priv;
target_t *target = info->target;
- u8 status;
+ uint8_t status;
if (oob_size)
davinci_write_block_data(nand, oob, 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, u32 page,
- u8 *data, u32 data_size, u8 *oob, u32 oob_size)
+static int davinci_write_page_ecc1(struct nand_device_s *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;
- const u32 fcr_addr = info->aemif + NANDFCR;
- const u32 ecc1_addr = info->aemif + NANDFECC + info->chipsel;
- u32 fcr, ecc1;
+ 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
ecc1 = ~ecc1;
/* save correct ECC code into oob data */
- oob[oob_offset++] = (u8)(ecc1);
- oob[oob_offset++] = (u8)(ecc1 >> 8);
- oob[oob_offset++] = (u8)(ecc1 >> 16);
+ oob[oob_offset++] = (uint8_t)(ecc1);
+ oob[oob_offset++] = (uint8_t)(ecc1 >> 8);
+ oob[oob_offset++] = (uint8_t)(ecc1 >> 16);
} while (data_size);
* 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, u32 page,
- u8 *data, u32 data_size, u8 *oob, u32 oob_size)
+static int davinci_write_page_ecc4(struct nand_device_s *nand, uint32_t page,
+ uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size)
{
- static const u8 ecc512[] = {
+ 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 u8 ecc2048[] = {
+ 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 u8 ecc4096[] = {
+ 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,
};
struct davinci_nand *info = nand->controller_priv;
- const u8 *l;
+ const uint8_t *l;
target_t *target = info->target;
- const u32 fcr_addr = info->aemif + NANDFCR;
- const u32 ecc4_addr = info->aemif + NAND4BITECC;
- u32 fcr, ecc4;
+ 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.
fcr |= (1 << 12) | (info->chipsel << 4);
do {
- u32 raw_ecc[4], *p;
+ uint32_t raw_ecc[4], *p;
int i;
/* start 4bit ecc on csX */
* 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, u32 page,
- u8 *data, u32 data_size, u8 *oob, u32 oob_size)
+static int davinci_write_page_ecc4infix(struct nand_device_s *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;
- const u32 fcr_addr = info->aemif + NANDFCR;
- const u32 ecc4_addr = info->aemif + NAND4BITECC;
- u32 fcr, ecc4;
+ 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);
fcr |= (1 << 12) | (info->chipsel << 4);
do {
- u32 raw_ecc[4], *p;
- u8 *l;
+ uint32_t raw_ecc[4], *p;
+ uint8_t *l;
int i;
/* start 4bit ecc on csX */
return davinci_writepage_tail(nand, NULL, 0);
}
-static int davinci_read_page_ecc4infix(struct nand_device_s *nand, u32 page,
- u8 *data, u32 data_size, u8 *oob, u32 oob_size)
+static int davinci_read_page_ecc4infix(struct nand_device_s *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);
}
aemif = strtoul(argv[4], &ep, 0);
- if (*ep || chip == 0 || chip == ULONG_MAX) {
+ if (*ep || aemif == 0 || aemif == ULONG_MAX) {
LOG_ERROR("Invalid AEMIF controller address %s", argv[4]);
goto fail;
}
|| 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.