From e1ec02bb055fa356b058dddc0a15710e0fdc9870 Mon Sep 17 00:00:00 2001 From: Zachary T Welch Date: Tue, 1 Dec 2009 22:37:11 -0800 Subject: move nand drivers to src/flash/nand/ Moves NAND drivers to src/flash/nand/. Adds src/flash/nand/Makefile.am. Builds libocdflashnand.la. --- configure.in | 1 + src/flash/Makefile.am | 26 +- src/flash/davinci_nand.c | 756 ------------------------------ src/flash/lpc3180_nand_controller.c | 910 ------------------------------------ src/flash/lpc3180_nand_controller.h | 40 -- src/flash/mx3_nand.c | 879 ---------------------------------- src/flash/mx3_nand.h | 117 ----- src/flash/nand/Makefile.am | 27 ++ src/flash/nand/davinci.c | 756 ++++++++++++++++++++++++++++++ src/flash/nand/lpc3180.c | 910 ++++++++++++++++++++++++++++++++++++ src/flash/nand/lpc3180.h | 40 ++ src/flash/nand/mx3.c | 879 ++++++++++++++++++++++++++++++++++ src/flash/nand/mx3.h | 117 +++++ src/flash/nand/nonce.c | 80 ++++ src/flash/nand/orion.c | 180 +++++++ src/flash/nand/s3c2410.c | 123 +++++ src/flash/nand/s3c2412.c | 79 ++++ src/flash/nand/s3c2440.c | 171 +++++++ src/flash/nand/s3c2443.c | 80 ++++ src/flash/nand/s3c24xx.c | 133 ++++++ src/flash/nand/s3c24xx.h | 84 ++++ src/flash/nand/s3c24xx_regs.h | 132 ++++++ src/flash/nonce_nand.c | 80 ---- src/flash/orion_nand.c | 180 ------- src/flash/s3c2410_nand.c | 123 ----- src/flash/s3c2412_nand.c | 79 ---- src/flash/s3c2440_nand.c | 171 ------- src/flash/s3c2443_nand.c | 80 ---- src/flash/s3c24xx_nand.c | 133 ------ src/flash/s3c24xx_nand.h | 84 ---- src/flash/s3c24xx_regs_nand.h | 132 ------ 31 files changed, 3799 insertions(+), 3783 deletions(-) delete mode 100644 src/flash/davinci_nand.c delete mode 100644 src/flash/lpc3180_nand_controller.c delete mode 100644 src/flash/lpc3180_nand_controller.h delete mode 100644 src/flash/mx3_nand.c delete mode 100644 src/flash/mx3_nand.h create mode 100644 src/flash/nand/Makefile.am create mode 100644 src/flash/nand/davinci.c create mode 100644 src/flash/nand/lpc3180.c create mode 100644 src/flash/nand/lpc3180.h create mode 100644 src/flash/nand/mx3.c create mode 100644 src/flash/nand/mx3.h create mode 100644 src/flash/nand/nonce.c create mode 100644 src/flash/nand/orion.c create mode 100644 src/flash/nand/s3c2410.c create mode 100644 src/flash/nand/s3c2412.c create mode 100644 src/flash/nand/s3c2440.c create mode 100644 src/flash/nand/s3c2443.c create mode 100644 src/flash/nand/s3c24xx.c create mode 100644 src/flash/nand/s3c24xx.h create mode 100644 src/flash/nand/s3c24xx_regs.h delete mode 100644 src/flash/nonce_nand.c delete mode 100644 src/flash/orion_nand.c delete mode 100644 src/flash/s3c2410_nand.c delete mode 100644 src/flash/s3c2412_nand.c delete mode 100644 src/flash/s3c2440_nand.c delete mode 100644 src/flash/s3c2443_nand.c delete mode 100644 src/flash/s3c24xx_nand.c delete mode 100644 src/flash/s3c24xx_nand.h delete mode 100644 src/flash/s3c24xx_regs_nand.h diff --git a/configure.in b/configure.in index dbddcb2b..3680cac5 100644 --- a/configure.in +++ b/configure.in @@ -1122,6 +1122,7 @@ AC_OUTPUT(dnl src/target/Makefile dnl src/server/Makefile dnl src/flash/Makefile dnl + src/flash/nand/Makefile dnl src/pld/Makefile dnl doc/Makefile dnl ) diff --git a/src/flash/Makefile.am b/src/flash/Makefile.am index 94cc86e5..353fcf16 100644 --- a/src/flash/Makefile.am +++ b/src/flash/Makefile.am @@ -1,3 +1,6 @@ +SUBDIRS = \ + nand + AM_CPPFLAGS = \ -I$(top_srcdir)/src/helper \ -I$(top_srcdir)/src/jtag \ @@ -10,6 +13,9 @@ libflash_la_SOURCES = \ $(NAND_SRCS) \ mflash.c +libflash_la_LIBADD = \ + $(top_builddir)/src/flash/nand/libocdflashnand.la + FLASH_SRCS = \ common.c \ cfi.c \ @@ -40,22 +46,8 @@ NAND_SRCS = \ arm_nandio.c \ nand_ecc.c \ nand_ecc_kw.c \ - $(NAND_DEVICES_SRCS) \ nand.c -NAND_DEVICES_SRCS = \ - nonce_nand.c \ - davinci_nand.c \ - lpc3180_nand_controller.c \ - mx3_nand.c \ - orion_nand.c \ - s3c24xx_nand.c \ - s3c2410_nand.c \ - s3c2412_nand.c \ - s3c2440_nand.c \ - s3c2443_nand.c - - noinst_HEADERS = \ arm_nandio.h \ at91sam7.h \ @@ -66,9 +58,7 @@ noinst_HEADERS = \ flash.h \ lpc2000.h \ lpc288x.h \ - lpc3180_nand_controller.h \ mflash.h \ - mx3_nand.h \ non_cfi.h \ nand.h \ ocl.h \ @@ -78,9 +68,7 @@ noinst_HEADERS = \ str7x.h \ str9x.h \ str9xpec.h \ - tms470.h \ - s3c24xx_nand.h \ - s3c24xx_regs_nand.h + tms470.h EXTRA_DIST = startup.tcl 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, -}; diff --git a/src/flash/lpc3180_nand_controller.c b/src/flash/lpc3180_nand_controller.c deleted file mode 100644 index 146c8438..00000000 --- a/src/flash/lpc3180_nand_controller.c +++ /dev/null @@ -1,910 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2007 by Dominic Rath * - * Dominic.Rath@gmx.de * - * * - * 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. * - ***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "lpc3180_nand_controller.h" -#include "nand.h" - -static int lpc3180_reset(struct nand_device *nand); -static int lpc3180_controller_ready(struct nand_device *nand, int timeout); - -/* nand device lpc3180 - */ -NAND_DEVICE_COMMAND_HANDLER(lpc3180_nand_device_command) -{ - if (CMD_ARGC < 3) - { - LOG_WARNING("incomplete 'lpc3180' nand flash configuration"); - return ERROR_FLASH_BANK_INVALID; - } - - struct target *target = get_target(CMD_ARGV[1]); - if (NULL == target) - { - LOG_ERROR("target '%s' not defined", CMD_ARGV[1]); - return ERROR_NAND_DEVICE_INVALID; - } - - uint32_t osc_freq; - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], osc_freq); - - struct lpc3180_nand_controller *lpc3180_info; - lpc3180_info = malloc(sizeof(struct lpc3180_nand_controller)); - nand->controller_priv = lpc3180_info; - - lpc3180_info->target = target; - lpc3180_info->osc_freq = osc_freq; - - if ((lpc3180_info->osc_freq < 1000) || (lpc3180_info->osc_freq > 20000)) - { - LOG_WARNING("LPC3180 oscillator frequency should be between 1000 and 20000 kHz, was %i", lpc3180_info->osc_freq); - } - lpc3180_info->selected_controller = LPC3180_NO_CONTROLLER; - lpc3180_info->sw_write_protection = 0; - lpc3180_info->sw_wp_lower_bound = 0x0; - lpc3180_info->sw_wp_upper_bound = 0x0; - - return ERROR_OK; -} - -static int lpc3180_pll(int fclkin, uint32_t pll_ctrl) -{ - int bypass = (pll_ctrl & 0x8000) >> 15; - int direct = (pll_ctrl & 0x4000) >> 14; - int feedback = (pll_ctrl & 0x2000) >> 13; - int p = (1 << ((pll_ctrl & 0x1800) >> 11) * 2); - int n = ((pll_ctrl & 0x0600) >> 9) + 1; - int m = ((pll_ctrl & 0x01fe) >> 1) + 1; - int lock = (pll_ctrl & 0x1); - - if (!lock) - LOG_WARNING("PLL is not locked"); - - if (!bypass && direct) /* direct mode */ - return (m * fclkin) / n; - - if (bypass && !direct) /* bypass mode */ - return fclkin / (2 * p); - - if (bypass & direct) /* direct bypass mode */ - return fclkin; - - if (feedback) /* integer mode */ - return m * (fclkin / n); - else /* non-integer mode */ - return (m / (2 * p)) * (fclkin / n); -} - -static float lpc3180_cycle_time(struct lpc3180_nand_controller *lpc3180_info) -{ - struct target *target = lpc3180_info->target; - uint32_t sysclk_ctrl, pwr_ctrl, hclkdiv_ctrl, hclkpll_ctrl; - int sysclk; - int hclk; - int hclk_pll; - float cycle; - - /* calculate timings */ - - /* determine current SYSCLK (13'MHz or main oscillator) */ - target_read_u32(target, 0x40004050, &sysclk_ctrl); - - if ((sysclk_ctrl & 1) == 0) - sysclk = lpc3180_info->osc_freq; - else - sysclk = 13000; - - /* determine selected HCLK source */ - target_read_u32(target, 0x40004044, &pwr_ctrl); - - if ((pwr_ctrl & (1 << 2)) == 0) /* DIRECT RUN mode */ - { - hclk = sysclk; - } - else - { - target_read_u32(target, 0x40004058, &hclkpll_ctrl); - hclk_pll = lpc3180_pll(sysclk, hclkpll_ctrl); - - target_read_u32(target, 0x40004040, &hclkdiv_ctrl); - - if (pwr_ctrl & (1 << 10)) /* ARM_CLK and HCLK use PERIPH_CLK */ - { - hclk = hclk_pll / (((hclkdiv_ctrl & 0x7c) >> 2) + 1); - } - else /* HCLK uses HCLK_PLL */ - { - hclk = hclk_pll / (1 << (hclkdiv_ctrl & 0x3)); - } - } - - LOG_DEBUG("LPC3180 HCLK currently clocked at %i kHz", hclk); - - cycle = (1.0 / hclk) * 1000000.0; - - return cycle; -} - -static int lpc3180_init(struct nand_device *nand) -{ - struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv; - struct target *target = lpc3180_info->target; - int bus_width = nand->bus_width ? : 8; - int address_cycles = nand->address_cycles ? : 3; - int page_size = nand->page_size ? : 512; - - if (target->state != TARGET_HALTED) - { - LOG_ERROR("target must be halted to use LPC3180 NAND flash controller"); - return ERROR_NAND_OPERATION_FAILED; - } - - /* sanitize arguments */ - if ((bus_width != 8) && (bus_width != 16)) - { - LOG_ERROR("LPC3180 only supports 8 or 16 bit bus width, not %i", bus_width); - return ERROR_NAND_OPERATION_NOT_SUPPORTED; - } - - /* The LPC3180 only brings out 8 bit NAND data bus, but the controller - * would support 16 bit, too, so we just warn about this for now - */ - if (bus_width == 16) - { - LOG_WARNING("LPC3180 only supports 8 bit bus width"); - } - - /* inform calling code about selected bus width */ - nand->bus_width = bus_width; - - if ((address_cycles != 3) && (address_cycles != 4)) - { - LOG_ERROR("LPC3180 only supports 3 or 4 address cycles, not %i", address_cycles); - return ERROR_NAND_OPERATION_NOT_SUPPORTED; - } - - if ((page_size != 512) && (page_size != 2048)) - { - LOG_ERROR("LPC3180 only supports 512 or 2048 byte pages, not %i", page_size); - return ERROR_NAND_OPERATION_NOT_SUPPORTED; - } - - /* select MLC controller if none is currently selected */ - if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER) - { - LOG_DEBUG("no LPC3180 NAND flash controller selected, using default 'mlc'"); - lpc3180_info->selected_controller = LPC3180_MLC_CONTROLLER; - } - - if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER) - { - uint32_t mlc_icr_value = 0x0; - float cycle; - int twp, twh, trp, treh, trhz, trbwb, tcea; - - /* FLASHCLK_CTRL = 0x22 (enable clock for MLC flash controller) */ - target_write_u32(target, 0x400040c8, 0x22); - - /* MLC_CEH = 0x0 (Force nCE assert) */ - target_write_u32(target, 0x200b804c, 0x0); - - /* MLC_LOCK = 0xa25e (unlock protected registers) */ - target_write_u32(target, 0x200b8044, 0xa25e); - - /* MLC_ICR = configuration */ - if (lpc3180_info->sw_write_protection) - mlc_icr_value |= 0x8; - if (page_size == 2048) - mlc_icr_value |= 0x4; - if (address_cycles == 4) - mlc_icr_value |= 0x2; - if (bus_width == 16) - mlc_icr_value |= 0x1; - target_write_u32(target, 0x200b8030, mlc_icr_value); - - /* calculate NAND controller timings */ - cycle = lpc3180_cycle_time(lpc3180_info); - - twp = ((40 / cycle) + 1); - twh = ((20 / cycle) + 1); - trp = ((30 / cycle) + 1); - treh = ((15 / cycle) + 1); - trhz = ((30 / cycle) + 1); - trbwb = ((100 / cycle) + 1); - tcea = ((45 / cycle) + 1); - - /* MLC_LOCK = 0xa25e (unlock protected registers) */ - target_write_u32(target, 0x200b8044, 0xa25e); - - /* MLC_TIME_REG */ - target_write_u32(target, 0x200b8034, (twp & 0xf) | ((twh & 0xf) << 4) | - ((trp & 0xf) << 8) | ((treh & 0xf) << 12) | ((trhz & 0x7) << 16) | - ((trbwb & 0x1f) << 19) | ((tcea & 0x3) << 24)); - - lpc3180_reset(nand); - } - else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER) - { - float cycle; - int r_setup, r_hold, r_width, r_rdy; - int w_setup, w_hold, w_width, w_rdy; - - /* FLASHCLK_CTRL = 0x05 (enable clock for SLC flash controller) */ - target_write_u32(target, 0x400040c8, 0x05); - - /* SLC_CFG = 0x (Force nCE assert, ECC enabled, WIDTH = bus_width) */ - target_write_u32(target, 0x20020014, 0x28 | (bus_width == 16) ? 1 : 0); - - /* calculate NAND controller timings */ - cycle = lpc3180_cycle_time(lpc3180_info); - - r_setup = w_setup = 0; - r_hold = w_hold = 10 / cycle; - r_width = 30 / cycle; - w_width = 40 / cycle; - r_rdy = w_rdy = 100 / cycle; - - /* SLC_TAC: SLC timing arcs register */ - target_write_u32(target, 0x2002002c, (r_setup & 0xf) | ((r_hold & 0xf) << 4) | - ((r_width & 0xf) << 8) | ((r_rdy & 0xf) << 12) | ((w_setup & 0xf) << 16) | - ((w_hold & 0xf) << 20) | ((w_width & 0xf) << 24) | ((w_rdy & 0xf) << 28)); - - lpc3180_reset(nand); - } - - return ERROR_OK; -} - -static int lpc3180_reset(struct nand_device *nand) -{ - struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv; - struct target *target = lpc3180_info->target; - - if (target->state != TARGET_HALTED) - { - LOG_ERROR("target must be halted to use LPC3180 NAND flash controller"); - return ERROR_NAND_OPERATION_FAILED; - } - - if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER) - { - LOG_ERROR("BUG: no LPC3180 NAND flash controller selected"); - return ERROR_NAND_OPERATION_FAILED; - } - else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER) - { - /* MLC_CMD = 0xff (reset controller and NAND device) */ - target_write_u32(target, 0x200b8000, 0xff); - - if (!lpc3180_controller_ready(nand, 100)) - { - LOG_ERROR("LPC3180 NAND controller timed out after reset"); - return ERROR_NAND_OPERATION_TIMEOUT; - } - } - else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER) - { - /* SLC_CTRL = 0x6 (ECC_CLEAR, SW_RESET) */ - target_write_u32(target, 0x20020010, 0x6); - - if (!lpc3180_controller_ready(nand, 100)) - { - LOG_ERROR("LPC3180 NAND controller timed out after reset"); - return ERROR_NAND_OPERATION_TIMEOUT; - } - } - - return ERROR_OK; -} - -static int lpc3180_command(struct nand_device *nand, uint8_t command) -{ - struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv; - struct target *target = lpc3180_info->target; - - if (target->state != TARGET_HALTED) - { - LOG_ERROR("target must be halted to use LPC3180 NAND flash controller"); - return ERROR_NAND_OPERATION_FAILED; - } - - if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER) - { - LOG_ERROR("BUG: no LPC3180 NAND flash controller selected"); - return ERROR_NAND_OPERATION_FAILED; - } - else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER) - { - /* MLC_CMD = command */ - target_write_u32(target, 0x200b8000, command); - } - else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER) - { - /* SLC_CMD = command */ - target_write_u32(target, 0x20020008, command); - } - - return ERROR_OK; -} - -static int lpc3180_address(struct nand_device *nand, uint8_t address) -{ - struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv; - struct target *target = lpc3180_info->target; - - if (target->state != TARGET_HALTED) - { - LOG_ERROR("target must be halted to use LPC3180 NAND flash controller"); - return ERROR_NAND_OPERATION_FAILED; - } - - if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER) - { - LOG_ERROR("BUG: no LPC3180 NAND flash controller selected"); - return ERROR_NAND_OPERATION_FAILED; - } - else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER) - { - /* MLC_ADDR = address */ - target_write_u32(target, 0x200b8004, address); - } - else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER) - { - /* SLC_ADDR = address */ - target_write_u32(target, 0x20020004, address); - } - - return ERROR_OK; -} - -static int lpc3180_write_data(struct nand_device *nand, uint16_t data) -{ - struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv; - struct target *target = lpc3180_info->target; - - if (target->state != TARGET_HALTED) - { - LOG_ERROR("target must be halted to use LPC3180 NAND flash controller"); - return ERROR_NAND_OPERATION_FAILED; - } - - if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER) - { - LOG_ERROR("BUG: no LPC3180 NAND flash controller selected"); - return ERROR_NAND_OPERATION_FAILED; - } - else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER) - { - /* MLC_DATA = data */ - target_write_u32(target, 0x200b0000, data); - } - else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER) - { - /* SLC_DATA = data */ - target_write_u32(target, 0x20020000, data); - } - - return ERROR_OK; -} - -static int lpc3180_read_data(struct nand_device *nand, void *data) -{ - struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv; - struct target *target = lpc3180_info->target; - - if (target->state != TARGET_HALTED) - { - LOG_ERROR("target must be halted to use LPC3180 NAND flash controller"); - return ERROR_NAND_OPERATION_FAILED; - } - - if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER) - { - LOG_ERROR("BUG: no LPC3180 NAND flash controller selected"); - return ERROR_NAND_OPERATION_FAILED; - } - else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER) - { - /* data = MLC_DATA, use sized access */ - if (nand->bus_width == 8) - { - uint8_t *data8 = data; - target_read_u8(target, 0x200b0000, data8); - } - else if (nand->bus_width == 16) - { - uint16_t *data16 = data; - target_read_u16(target, 0x200b0000, data16); - } - else - { - LOG_ERROR("BUG: bus_width neither 8 nor 16 bit"); - return ERROR_NAND_OPERATION_FAILED; - } - } - else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER) - { - uint32_t data32; - - /* data = SLC_DATA, must use 32-bit access */ - target_read_u32(target, 0x20020000, &data32); - - if (nand->bus_width == 8) - { - uint8_t *data8 = data; - *data8 = data32 & 0xff; - } - else if (nand->bus_width == 16) - { - uint16_t *data16 = data; - *data16 = data32 & 0xffff; - } - else - { - LOG_ERROR("BUG: bus_width neither 8 nor 16 bit"); - return ERROR_NAND_OPERATION_FAILED; - } - } - - return ERROR_OK; -} - -static int lpc3180_write_page(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) -{ - struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv; - struct target *target = lpc3180_info->target; - int retval; - uint8_t status; - - if (target->state != TARGET_HALTED) - { - LOG_ERROR("target must be halted to use LPC3180 NAND flash controller"); - return ERROR_NAND_OPERATION_FAILED; - } - - if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER) - { - LOG_ERROR("BUG: no LPC3180 NAND flash controller selected"); - return ERROR_NAND_OPERATION_FAILED; - } - else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER) - { - uint8_t *page_buffer; - uint8_t *oob_buffer; - int quarter, num_quarters; - - if (!data && oob) - { - LOG_ERROR("LPC3180 MLC controller can't write OOB data only"); - return ERROR_NAND_OPERATION_NOT_SUPPORTED; - } - - if (oob && (oob_size > 6)) - { - LOG_ERROR("LPC3180 MLC controller can't write more than 6 bytes of OOB data"); - return ERROR_NAND_OPERATION_NOT_SUPPORTED; - } - - if (data_size > (uint32_t)nand->page_size) - { - LOG_ERROR("data size exceeds page size"); - return ERROR_NAND_OPERATION_NOT_SUPPORTED; - } - - /* MLC_CMD = sequential input */ - target_write_u32(target, 0x200b8000, NAND_CMD_SEQIN); - - page_buffer = malloc(512); - oob_buffer = malloc(6); - - if (nand->page_size == 512) - { - /* MLC_ADDR = 0x0 (one column cycle) */ - target_write_u32(target, 0x200b8004, 0x0); - - /* MLC_ADDR = row */ - target_write_u32(target, 0x200b8004, page & 0xff); - target_write_u32(target, 0x200b8004, (page >> 8) & 0xff); - - if (nand->address_cycles == 4) - target_write_u32(target, 0x200b8004, (page >> 16) & 0xff); - } - else - { - /* MLC_ADDR = 0x0 (two column cycles) */ - target_write_u32(target, 0x200b8004, 0x0); - target_write_u32(target, 0x200b8004, 0x0); - - /* MLC_ADDR = row */ - target_write_u32(target, 0x200b8004, page & 0xff); - target_write_u32(target, 0x200b8004, (page >> 8) & 0xff); - } - - /* when using the MLC controller, we have to treat a large page device - * as being made out of four quarters, each the size of a small page device - */ - num_quarters = (nand->page_size == 2048) ? 4 : 1; - - for (quarter = 0; quarter < num_quarters; quarter++) - { - int thisrun_data_size = (data_size > 512) ? 512 : data_size; - int thisrun_oob_size = (oob_size > 6) ? 6 : oob_size; - - memset(page_buffer, 0xff, 512); - if (data) - { - memcpy(page_buffer, data, thisrun_data_size); - data_size -= thisrun_data_size; - data += thisrun_data_size; - } - - memset(oob_buffer, 0xff, (nand->page_size == 512) ? 6 : 24); - if (oob) - { - memcpy(page_buffer, oob, thisrun_oob_size); - oob_size -= thisrun_oob_size; - oob += thisrun_oob_size; - } - - /* write MLC_ECC_ENC_REG to start encode cycle */ - target_write_u32(target, 0x200b8008, 0x0); - - target_write_memory(target, 0x200a8000, 4, 128, page_buffer + (quarter * 512)); - target_write_memory(target, 0x200a8000, 1, 6, oob_buffer + (quarter * 6)); - - /* write MLC_ECC_AUTO_ENC_REG to start auto encode */ - target_write_u32(target, 0x200b8010, 0x0); - - if (!lpc3180_controller_ready(nand, 1000)) - { - LOG_ERROR("timeout while waiting for completion of auto encode cycle"); - return ERROR_NAND_OPERATION_FAILED; - } - } - - /* MLC_CMD = auto program command */ - target_write_u32(target, 0x200b8000, NAND_CMD_PAGEPROG); - - if ((retval = 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 didn't pass, status: 0x%2.2x", status); - return ERROR_NAND_OPERATION_FAILED; - } - - free(page_buffer); - free(oob_buffer); - } - else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER) - { - return nand_write_page_raw(nand, page, data, data_size, oob, oob_size); - } - - return ERROR_OK; -} - -static int lpc3180_read_page(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) -{ - struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv; - struct target *target = lpc3180_info->target; - - if (target->state != TARGET_HALTED) - { - LOG_ERROR("target must be halted to use LPC3180 NAND flash controller"); - return ERROR_NAND_OPERATION_FAILED; - } - - if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER) - { - LOG_ERROR("BUG: no LPC3180 NAND flash controller selected"); - return ERROR_NAND_OPERATION_FAILED; - } - else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER) - { - uint8_t *page_buffer; - uint8_t *oob_buffer; - uint32_t page_bytes_done = 0; - uint32_t oob_bytes_done = 0; - uint32_t mlc_isr; - -#if 0 - if (oob && (oob_size > 6)) - { - LOG_ERROR("LPC3180 MLC controller can't read more than 6 bytes of OOB data"); - return ERROR_NAND_OPERATION_NOT_SUPPORTED; - } -#endif - - if (data_size > (uint32_t)nand->page_size) - { - LOG_ERROR("data size exceeds page size"); - return ERROR_NAND_OPERATION_NOT_SUPPORTED; - } - - if (nand->page_size == 2048) - { - page_buffer = malloc(2048); - oob_buffer = malloc(64); - } - else - { - page_buffer = malloc(512); - oob_buffer = malloc(16); - } - - if (!data && oob) - { - /* MLC_CMD = Read OOB - * we can use the READOOB command on both small and large page devices, - * as the controller translates the 0x50 command to a 0x0 with appropriate - * positioning of the serial buffer read pointer - */ - target_write_u32(target, 0x200b8000, NAND_CMD_READOOB); - } - else - { - /* MLC_CMD = Read0 */ - target_write_u32(target, 0x200b8000, NAND_CMD_READ0); - } - - if (nand->page_size == 512) - { - /* small page device */ - /* MLC_ADDR = 0x0 (one column cycle) */ - target_write_u32(target, 0x200b8004, 0x0); - - /* MLC_ADDR = row */ - target_write_u32(target, 0x200b8004, page & 0xff); - target_write_u32(target, 0x200b8004, (page >> 8) & 0xff); - - if (nand->address_cycles == 4) - target_write_u32(target, 0x200b8004, (page >> 16) & 0xff); - } - else - { - /* large page device */ - /* MLC_ADDR = 0x0 (two column cycles) */ - target_write_u32(target, 0x200b8004, 0x0); - target_write_u32(target, 0x200b8004, 0x0); - - /* MLC_ADDR = row */ - target_write_u32(target, 0x200b8004, page & 0xff); - target_write_u32(target, 0x200b8004, (page >> 8) & 0xff); - - /* MLC_CMD = Read Start */ - target_write_u32(target, 0x200b8000, NAND_CMD_READSTART); - } - - while (page_bytes_done < (uint32_t)nand->page_size) - { - /* MLC_ECC_AUTO_DEC_REG = dummy */ - target_write_u32(target, 0x200b8014, 0xaa55aa55); - - if (!lpc3180_controller_ready(nand, 1000)) - { - LOG_ERROR("timeout while waiting for completion of auto decode cycle"); - return ERROR_NAND_OPERATION_FAILED; - } - - target_read_u32(target, 0x200b8048, &mlc_isr); - - if (mlc_isr & 0x8) - { - if (mlc_isr & 0x40) - { - LOG_ERROR("uncorrectable error detected: 0x%2.2x", (unsigned)mlc_isr); - return ERROR_NAND_OPERATION_FAILED; - } - - LOG_WARNING("%i symbol error detected and corrected", ((int)(((mlc_isr & 0x30) >> 4) + 1))); - } - - if (data) - { - target_read_memory(target, 0x200a8000, 4, 128, page_buffer + page_bytes_done); - } - - if (oob) - { - target_read_memory(target, 0x200a8000, 4, 4, oob_buffer + oob_bytes_done); - } - - page_bytes_done += 512; - oob_bytes_done += 16; - } - - if (data) - memcpy(data, page_buffer, data_size); - - if (oob) - memcpy(oob, oob_buffer, oob_size); - - free(page_buffer); - free(oob_buffer); - } - else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER) - { - return nand_read_page_raw(nand, page, data, data_size, oob, oob_size); - } - - return ERROR_OK; -} - -static int lpc3180_controller_ready(struct nand_device *nand, int timeout) -{ - struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv; - struct target *target = lpc3180_info->target; - uint8_t status = 0x0; - - if (target->state != TARGET_HALTED) - { - LOG_ERROR("target must be halted to use LPC3180 NAND flash controller"); - return ERROR_NAND_OPERATION_FAILED; - } - - do - { - if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER) - { - /* Read MLC_ISR, wait for controller to become ready */ - target_read_u8(target, 0x200b8048, &status); - - if (status & 2) - return 1; - } - else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER) - { - /* we pretend that the SLC controller is always ready */ - return 1; - } - - alive_sleep(1); - } while (timeout-- > 0); - - return 0; -} - -static int lpc3180_nand_ready(struct nand_device *nand, int timeout) -{ - struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv; - struct target *target = lpc3180_info->target; - - if (target->state != TARGET_HALTED) - { - LOG_ERROR("target must be halted to use LPC3180 NAND flash controller"); - return ERROR_NAND_OPERATION_FAILED; - } - - do - { - if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER) - { - uint8_t status = 0x0; - - /* Read MLC_ISR, wait for NAND flash device to become ready */ - target_read_u8(target, 0x200b8048, &status); - - if (status & 1) - return 1; - } - else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER) - { - uint32_t status = 0x0; - - /* Read SLC_STAT and check READY bit */ - target_read_u32(target, 0x20020018, &status); - - if (status & 1) - return 1; - } - - alive_sleep(1); - } while (timeout-- > 0); - - return 0; -} - -COMMAND_HANDLER(handle_lpc3180_select_command) -{ - struct lpc3180_nand_controller *lpc3180_info = NULL; - char *selected[] = - { - "no", "mlc", "slc" - }; - - if ((CMD_ARGC < 1) || (CMD_ARGC > 2)) - { - return ERROR_COMMAND_SYNTAX_ERROR; - } - - unsigned num; - COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], num); - struct nand_device *nand = get_nand_device_by_num(num); - if (!nand) - { - command_print(CMD_CTX, "nand device '#%s' is out of bounds", CMD_ARGV[0]); - return ERROR_OK; - } - - lpc3180_info = nand->controller_priv; - - if (CMD_ARGC == 2) - { - if (strcmp(CMD_ARGV[1], "mlc") == 0) - { - lpc3180_info->selected_controller = LPC3180_MLC_CONTROLLER; - } - else if (strcmp(CMD_ARGV[1], "slc") == 0) - { - lpc3180_info->selected_controller = LPC3180_SLC_CONTROLLER; - } - else - { - return ERROR_COMMAND_SYNTAX_ERROR; - } - } - - command_print(CMD_CTX, "%s controller selected", selected[lpc3180_info->selected_controller]); - - return ERROR_OK; -} - -static const struct command_registration lpc3180_exec_command_handlers[] = { - { - .name = "select", - .handler = &handle_lpc3180_select_command, - .mode = COMMAND_EXEC, - .help = "select <'mlc'|'slc'> controller (default is mlc)", - .usage = " (mlc|slc)", - }, - COMMAND_REGISTRATION_DONE -}; -static const struct command_registration lpc3180_command_handler[] = { - { - .name = "lpc3180", - .mode = COMMAND_ANY, - .help = "LPC3180 NAND flash controller commands", - .chain = lpc3180_exec_command_handlers, - }, - COMMAND_REGISTRATION_DONE -}; - -struct nand_flash_controller lpc3180_nand_controller = { - .name = "lpc3180", - .commands = lpc3180_command_handler, - .nand_device_command = lpc3180_nand_device_command, - .init = lpc3180_init, - .reset = lpc3180_reset, - .command = lpc3180_command, - .address = lpc3180_address, - .write_data = lpc3180_write_data, - .read_data = lpc3180_read_data, - .write_page = lpc3180_write_page, - .read_page = lpc3180_read_page, - .controller_ready = lpc3180_controller_ready, - .nand_ready = lpc3180_nand_ready, - }; diff --git a/src/flash/lpc3180_nand_controller.h b/src/flash/lpc3180_nand_controller.h deleted file mode 100644 index 0891cedf..00000000 --- a/src/flash/lpc3180_nand_controller.h +++ /dev/null @@ -1,40 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2007 by Dominic Rath * - * Dominic.Rath@gmx.de * - * * - * 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. * - ***************************************************************************/ -#ifndef LPC3180_NAND_CONTROLLER_H -#define LPC3180_NAND_CONTROLLER_H - -enum lpc3180_selected_controller -{ - LPC3180_NO_CONTROLLER, - LPC3180_MLC_CONTROLLER, - LPC3180_SLC_CONTROLLER, -}; - -struct lpc3180_nand_controller -{ - struct target *target; - int osc_freq; - enum lpc3180_selected_controller selected_controller; - int sw_write_protection; - uint32_t sw_wp_lower_bound; - uint32_t sw_wp_upper_bound; -}; - -#endif /*LPC3180_NAND_CONTROLLER_H */ diff --git a/src/flash/mx3_nand.c b/src/flash/mx3_nand.c deleted file mode 100644 index 1dc4fcbc..00000000 --- a/src/flash/mx3_nand.c +++ /dev/null @@ -1,879 +0,0 @@ - -/*************************************************************************** - * Copyright (C) 2009 by Alexei Babich * - * Rezonans plc., Chelyabinsk, Russia * - * impatt@mail.ru * - * * - * 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. * - ***************************************************************************/ - -/* - * Freescale iMX3* OpenOCD NAND Flash controller support. - * - * Many thanks to Ben Dooks for writing s3c24xx driver. - */ - -/* -driver tested with STMicro NAND512W3A @imx31 -tested "nand probe #", "nand erase # 0 #", "nand dump # file 0 #", "nand write # file 0" -get_next_halfword_from_sram_buffer() not tested -*/ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "mx3_nand.h" - -static const char target_not_halted_err_msg[] = - "target must be halted to use mx3 NAND flash controller"; -static const char data_block_size_err_msg[] = - "minimal granularity is one half-word, %" PRId32 " is incorrect"; -static const char sram_buffer_bounds_err_msg[] = - "trying to access out of SRAM buffer bound (addr=0x%" PRIx32 ")"; -static const char get_status_register_err_msg[] = "can't get NAND status"; -static uint32_t in_sram_address; -unsigned char sign_of_sequental_byte_read; - -static int test_iomux_settings (struct target * target, uint32_t value, - uint32_t mask, const char *text); -static int initialize_nf_controller (struct nand_device *nand); -static int get_next_byte_from_sram_buffer (struct target * target, uint8_t * value); -static int get_next_halfword_from_sram_buffer (struct target * target, - uint16_t * value); -static int poll_for_complete_op (struct target * target, const char *text); -static int validate_target_state (struct nand_device *nand); -static int do_data_output (struct nand_device *nand); - -static int imx31_command (struct nand_device *nand, uint8_t command); -static int imx31_address (struct nand_device *nand, uint8_t address); -static int imx31_controller_ready (struct nand_device *nand, int tout); - -NAND_DEVICE_COMMAND_HANDLER(imx31_nand_device_command) -{ - struct mx3_nf_controller *mx3_nf_info; - mx3_nf_info = malloc (sizeof (struct mx3_nf_controller)); - if (mx3_nf_info == NULL) - { - LOG_ERROR ("no memory for nand controller"); - return ERROR_FAIL; - } - - nand->controller_priv = mx3_nf_info; - - mx3_nf_info->target = get_target (CMD_ARGV[1]); - if (mx3_nf_info->target == NULL) - { - LOG_ERROR ("target '%s' not defined", CMD_ARGV[1]); - return ERROR_FAIL; - } - if (CMD_ARGC < 3) - { - LOG_ERROR ("use \"nand device imx31 target noecc|hwecc\""); - return ERROR_FAIL; - } - /* - * check hwecc requirements - */ - { - int hwecc_needed; - hwecc_needed = strcmp (CMD_ARGV[2], "hwecc"); - if (hwecc_needed == 0) - { - mx3_nf_info->flags.hw_ecc_enabled = 1; - } - else - { - mx3_nf_info->flags.hw_ecc_enabled = 0; - } - } - - mx3_nf_info->optype = MX3_NF_DATAOUT_PAGE; - mx3_nf_info->fin = MX3_NF_FIN_NONE; - mx3_nf_info->flags.target_little_endian = - (mx3_nf_info->target->endianness == TARGET_LITTLE_ENDIAN); - /* - * testing host endianess - */ - { - int x = 1; - if (*(char *) &x == 1) - { - mx3_nf_info->flags.host_little_endian = 1; - } - else - { - mx3_nf_info->flags.host_little_endian = 0; - } - } - return ERROR_OK; -} - -static int imx31_init (struct nand_device *nand) -{ - struct mx3_nf_controller *mx3_nf_info = nand->controller_priv; - struct target *target = mx3_nf_info->target; - - { - /* - * validate target state - */ - int validate_target_result; - validate_target_result = validate_target_state(nand); - if (validate_target_result != ERROR_OK) - { - return validate_target_result; - } - } - - { - uint16_t buffsize_register_content; - target_read_u16 (target, MX3_NF_BUFSIZ, &buffsize_register_content); - mx3_nf_info->flags.one_kb_sram = !(buffsize_register_content & 0x000f); - } - - { - uint32_t pcsr_register_content; - target_read_u32 (target, MX3_PCSR, &pcsr_register_content); - if (!nand->bus_width) - { - nand->bus_width = - (pcsr_register_content & 0x80000000) ? 16 : 8; - } - else - { - pcsr_register_content |= - ((nand->bus_width == 16) ? 0x80000000 : 0x00000000); - target_write_u32 (target, MX3_PCSR, pcsr_register_content); - } - - if (!nand->page_size) - { - nand->page_size = - (pcsr_register_content & 0x40000000) ? 2048 : 512; - } - else - { - pcsr_register_content |= - ((nand->page_size == 2048) ? 0x40000000 : 0x00000000); - target_write_u32 (target, MX3_PCSR, pcsr_register_content); - } - if (mx3_nf_info->flags.one_kb_sram && (nand->page_size == 2048)) - { - LOG_ERROR - ("NAND controller have only 1 kb SRAM, so pagesize 2048 is incompatible with it"); - } - } - - { - uint32_t cgr_register_content; - target_read_u32 (target, MX3_CCM_CGR2, &cgr_register_content); - if (!(cgr_register_content & 0x00000300)) - { - LOG_ERROR ("clock gating to EMI disabled"); - return ERROR_FAIL; - } - } - - { - uint32_t gpr_register_content; - target_read_u32 (target, MX3_GPR, &gpr_register_content); - if (gpr_register_content & 0x00000060) - { - LOG_ERROR ("pins mode overrided by GPR"); - return ERROR_FAIL; - } - } - - { - /* - * testing IOMUX settings; must be in "functional-mode output and - * functional-mode input" mode - */ - int test_iomux; - test_iomux = ERROR_OK; - test_iomux |= - test_iomux_settings (target, 0x43fac0c0, 0x7f7f7f00, "d0,d1,d2"); - test_iomux |= - test_iomux_settings (target, 0x43fac0c4, 0x7f7f7f7f, "d3,d4,d5,d6"); - test_iomux |= - test_iomux_settings (target, 0x43fac0c8, 0x0000007f, "d7"); - if (nand->bus_width == 16) - { - test_iomux |= - test_iomux_settings (target, 0x43fac0c8, 0x7f7f7f00, - "d8,d9,d10"); - test_iomux |= - test_iomux_settings (target, 0x43fac0cc, 0x7f7f7f7f, - "d11,d12,d13,d14"); - test_iomux |= - test_iomux_settings (target, 0x43fac0d0, 0x0000007f, "d15"); - } - test_iomux |= - test_iomux_settings (target, 0x43fac0d0, 0x7f7f7f00, - "nfwp,nfce,nfrb"); - test_iomux |= - test_iomux_settings (target, 0x43fac0d4, 0x7f7f7f7f, - "nfwe,nfre,nfale,nfcle"); - if (test_iomux != ERROR_OK) - { - return ERROR_FAIL; - } - } - - initialize_nf_controller (nand); - - { - int retval; - uint16_t nand_status_content; - retval = ERROR_OK; - retval |= imx31_command (nand, NAND_CMD_STATUS); - retval |= imx31_address (nand, 0x00); - retval |= do_data_output (nand); - if (retval != ERROR_OK) - { - LOG_ERROR (get_status_register_err_msg); - return ERROR_FAIL; - } - target_read_u16 (target, MX3_NF_MAIN_BUFFER0, &nand_status_content); - if (!(nand_status_content & 0x0080)) - { - /* - * is host-big-endian correctly ?? - */ - LOG_INFO ("NAND read-only"); - mx3_nf_info->flags.nand_readonly = 1; - } - else - { - mx3_nf_info->flags.nand_readonly = 0; - } - } - return ERROR_OK; -} - -static int imx31_read_data (struct nand_device *nand, void *data) -{ - struct mx3_nf_controller *mx3_nf_info = nand->controller_priv; - struct target *target = mx3_nf_info->target; - { - /* - * validate target state - */ - int validate_target_result; - validate_target_result = validate_target_state (nand); - if (validate_target_result != ERROR_OK) - { - return validate_target_result; - } - } - - { - /* - * get data from nand chip - */ - int try_data_output_from_nand_chip; - try_data_output_from_nand_chip = do_data_output (nand); - if (try_data_output_from_nand_chip != ERROR_OK) - { - return try_data_output_from_nand_chip; - } - } - - if (nand->bus_width == 16) - { - get_next_halfword_from_sram_buffer (target, data); - } - else - { - get_next_byte_from_sram_buffer (target, data); - } - - return ERROR_OK; -} - -static int imx31_write_data (struct nand_device *nand, uint16_t data) -{ - LOG_ERROR ("write_data() not implemented"); - return ERROR_NAND_OPERATION_FAILED; -} - -static int imx31_nand_ready (struct nand_device *nand, int timeout) -{ - return imx31_controller_ready (nand, timeout); -} - -static int imx31_reset (struct nand_device *nand) -{ - /* - * validate target state - */ - int validate_target_result; - validate_target_result = validate_target_state (nand); - if (validate_target_result != ERROR_OK) - { - return validate_target_result; - } - initialize_nf_controller (nand); - return ERROR_OK; -} - -static int imx31_command (struct nand_device *nand, uint8_t command) -{ - struct mx3_nf_controller *mx3_nf_info = nand->controller_priv; - struct target *target = mx3_nf_info->target; - { - /* - * validate target state - */ - int validate_target_result; - validate_target_result = validate_target_state (nand); - if (validate_target_result != ERROR_OK) - { - return validate_target_result; - } - } - - switch (command) - { - case NAND_CMD_READOOB: - command = NAND_CMD_READ0; - in_sram_address = MX3_NF_SPARE_BUFFER0; /* set read point for - * data_read() and - * read_block_data() to - * spare area in SRAM - * buffer */ - break; - case NAND_CMD_READ1: - command = NAND_CMD_READ0; - /* - * offset == one half of page size - */ - in_sram_address = - MX3_NF_MAIN_BUFFER0 + (nand->page_size >> 1); - default: - in_sram_address = MX3_NF_MAIN_BUFFER0; - } - - target_write_u16 (target, MX3_NF_FCMD, command); - /* - * start command input operation (set MX3_NF_BIT_OP_DONE==0) - */ - target_write_u16 (target, MX3_NF_CFG2, MX3_NF_BIT_OP_FCI); - { - int poll_result; - poll_result = poll_for_complete_op (target, "command"); - if (poll_result != ERROR_OK) - { - return poll_result; - } - } - /* - * reset cursor to begin of the buffer - */ - sign_of_sequental_byte_read = 0; - switch (command) - { - case NAND_CMD_READID: - mx3_nf_info->optype = MX3_NF_DATAOUT_NANDID; - mx3_nf_info->fin = MX3_NF_FIN_DATAOUT; - break; - case NAND_CMD_STATUS: - mx3_nf_info->optype = MX3_NF_DATAOUT_NANDSTATUS; - mx3_nf_info->fin = MX3_NF_FIN_DATAOUT; - break; - case NAND_CMD_READ0: - mx3_nf_info->fin = MX3_NF_FIN_DATAOUT; - mx3_nf_info->optype = MX3_NF_DATAOUT_PAGE; - break; - default: - mx3_nf_info->optype = MX3_NF_DATAOUT_PAGE; - } - return ERROR_OK; -} - -static int imx31_address (struct nand_device *nand, uint8_t address) -{ - struct mx3_nf_controller *mx3_nf_info = nand->controller_priv; - struct target *target = mx3_nf_info->target; - { - /* - * validate target state - */ - int validate_target_result; - validate_target_result = validate_target_state (nand); - if (validate_target_result != ERROR_OK) - { - return validate_target_result; - } - } - - target_write_u16 (target, MX3_NF_FADDR, address); - /* - * start address input operation (set MX3_NF_BIT_OP_DONE==0) - */ - target_write_u16 (target, MX3_NF_CFG2, MX3_NF_BIT_OP_FAI); - { - int poll_result; - poll_result = poll_for_complete_op (target, "address"); - if (poll_result != ERROR_OK) - { - return poll_result; - } - } - return ERROR_OK; -} - -static int imx31_controller_ready (struct nand_device *nand, int tout) -{ - uint16_t poll_complete_status; - struct mx3_nf_controller *mx3_nf_info = nand->controller_priv; - struct target *target = mx3_nf_info->target; - - { - /* - * validate target state - */ - int validate_target_result; - validate_target_result = validate_target_state (nand); - if (validate_target_result != ERROR_OK) - { - return validate_target_result; - } - } - - do - { - target_read_u16 (target, MX3_NF_CFG2, &poll_complete_status); - if (poll_complete_status & MX3_NF_BIT_OP_DONE) - { - return tout; - } - alive_sleep (1); - } - while (tout-- > 0); - return tout; -} - -static int imx31_write_page (struct nand_device *nand, uint32_t page, - uint8_t * data, uint32_t data_size, uint8_t * oob, - uint32_t oob_size) -{ - struct mx3_nf_controller *mx3_nf_info = nand->controller_priv; - struct target *target = mx3_nf_info->target; - - if (data_size % 2) - { - LOG_ERROR (data_block_size_err_msg, data_size); - return ERROR_NAND_OPERATION_FAILED; - } - if (oob_size % 2) - { - LOG_ERROR (data_block_size_err_msg, oob_size); - return ERROR_NAND_OPERATION_FAILED; - } - if (!data) - { - LOG_ERROR ("nothing to program"); - return ERROR_NAND_OPERATION_FAILED; - } - { - /* - * validate target state - */ - int retval; - retval = validate_target_state (nand); - if (retval != ERROR_OK) - { - return retval; - } - } - { - int retval = ERROR_OK; - retval |= imx31_command(nand, NAND_CMD_SEQIN); - retval |= imx31_address(nand, 0x00); - retval |= imx31_address(nand, page & 0xff); - retval |= imx31_address(nand, (page >> 8) & 0xff); - if (nand->address_cycles >= 4) - { - retval |= imx31_address (nand, (page >> 16) & 0xff); - if (nand->address_cycles >= 5) - { - retval |= imx31_address (nand, (page >> 24) & 0xff); - } - } - target_write_buffer (target, MX3_NF_MAIN_BUFFER0, data_size, data); - if (oob) - { - if (mx3_nf_info->flags.hw_ecc_enabled) - { - /* - * part of spare block will be overrided by hardware - * ECC generator - */ - LOG_DEBUG - ("part of spare block will be overrided by hardware ECC generator"); - } - target_write_buffer (target, MX3_NF_SPARE_BUFFER0, oob_size, - oob); - } - /* - * start data input operation (set MX3_NF_BIT_OP_DONE==0) - */ - target_write_u16 (target, MX3_NF_CFG2, MX3_NF_BIT_OP_FDI); - { - int poll_result; - poll_result = poll_for_complete_op (target, "data input"); - if (poll_result != ERROR_OK) - { - return poll_result; - } - } - retval |= imx31_command (nand, NAND_CMD_PAGEPROG); - if (retval != ERROR_OK) - { - return retval; - } - - /* - * check status register - */ - { - uint16_t nand_status_content; - retval = ERROR_OK; - retval |= imx31_command(nand, NAND_CMD_STATUS); - retval |= imx31_address(nand, 0x00); - retval |= do_data_output(nand); - if (retval != ERROR_OK) - { - LOG_ERROR (get_status_register_err_msg); - return retval; - } - target_read_u16 (target, MX3_NF_MAIN_BUFFER0, &nand_status_content); - if (nand_status_content & 0x0001) - { - /* - * is host-big-endian correctly ?? - */ - return ERROR_NAND_OPERATION_FAILED; - } - } - } - return ERROR_OK; -} - -static int imx31_read_page (struct nand_device *nand, uint32_t page, - uint8_t * data, uint32_t data_size, uint8_t * oob, - uint32_t oob_size) -{ - struct mx3_nf_controller *mx3_nf_info = nand->controller_priv; - struct target *target = mx3_nf_info->target; - - if (data_size % 2) - { - LOG_ERROR (data_block_size_err_msg, data_size); - return ERROR_NAND_OPERATION_FAILED; - } - if (oob_size % 2) - { - LOG_ERROR (data_block_size_err_msg, oob_size); - return ERROR_NAND_OPERATION_FAILED; - } - - { - /* - * validate target state - */ - int retval; - retval = validate_target_state(nand); - if (retval != ERROR_OK) - { - return retval; - } - } - { - int retval = ERROR_OK; - retval |= imx31_command(nand, NAND_CMD_READ0); - retval |= imx31_address(nand, 0x00); - retval |= imx31_address(nand, page & 0xff); - retval |= imx31_address(nand, (page >> 8) & 0xff); - if (nand->address_cycles >= 4) - { - retval |= imx31_address(nand, (page >> 16) & 0xff); - if (nand->address_cycles >= 5) - { - retval |= imx31_address(nand, (page >> 24) & 0xff); - retval |= imx31_command(nand, NAND_CMD_READSTART); - } - } - retval |= do_data_output (nand); - if (retval != ERROR_OK) - { - return retval; - } - - if (data) - { - target_read_buffer (target, MX3_NF_MAIN_BUFFER0, data_size, - data); - } - if (oob) - { - target_read_buffer (target, MX3_NF_SPARE_BUFFER0, oob_size, - oob); - } - } - return ERROR_OK; -} - -static int test_iomux_settings (struct target * target, uint32_t address, - uint32_t mask, const char *text) -{ - uint32_t register_content; - target_read_u32 (target, address, ®ister_content); - if ((register_content & mask) != (0x12121212 & mask)) - { - LOG_ERROR ("IOMUX for {%s} is bad", text); - return ERROR_FAIL; - } - return ERROR_OK; -} - -static int initialize_nf_controller (struct nand_device *nand) -{ - struct mx3_nf_controller *mx3_nf_info = nand->controller_priv; - struct target *target = mx3_nf_info->target; - /* - * resets NAND flash controller in zero time ? I dont know. - */ - target_write_u16 (target, MX3_NF_CFG1, MX3_NF_BIT_RESET_EN); - { - uint16_t work_mode; - work_mode = MX3_NF_BIT_INT_DIS; /* disable interrupt */ - if (target->endianness == TARGET_BIG_ENDIAN) - { - work_mode |= MX3_NF_BIT_BE_EN; - } - if (mx3_nf_info->flags.hw_ecc_enabled) - { - work_mode |= MX3_NF_BIT_ECC_EN; - } - target_write_u16 (target, MX3_NF_CFG1, work_mode); - } - /* - * unlock SRAM buffer for write; 2 mean "Unlock", other values means "Lock" - */ - target_write_u16 (target, MX3_NF_BUFCFG, 2); - { - uint16_t temp; - target_read_u16 (target, MX3_NF_FWP, &temp); - if ((temp & 0x0007) == 1) - { - LOG_ERROR ("NAND flash is tight-locked, reset needed"); - return ERROR_FAIL; - } - - } - /* - * unlock NAND flash for write - */ - target_write_u16 (target, MX3_NF_FWP, 4); - target_write_u16 (target, MX3_NF_LOCKSTART, 0x0000); - target_write_u16 (target, MX3_NF_LOCKEND, 0xFFFF); - /* - * 0x0000 means that first SRAM buffer @0xB800_0000 will be used - */ - target_write_u16 (target, MX3_NF_BUFADDR, 0x0000); - /* - * address of SRAM buffer - */ - in_sram_address = MX3_NF_MAIN_BUFFER0; - sign_of_sequental_byte_read = 0; - return ERROR_OK; -} - -static int get_next_byte_from_sram_buffer (struct target * target, uint8_t * value) -{ - static uint8_t even_byte = 0; - /* - * host-big_endian ?? - */ - if (sign_of_sequental_byte_read == 0) - { - even_byte = 0; - } - if (in_sram_address > MX3_NF_LAST_BUFFER_ADDR) - { - LOG_ERROR (sram_buffer_bounds_err_msg, in_sram_address); - *value = 0; - sign_of_sequental_byte_read = 0; - even_byte = 0; - return ERROR_NAND_OPERATION_FAILED; - } - else - { - uint16_t temp; - target_read_u16 (target, in_sram_address, &temp); - if (even_byte) - { - *value = temp >> 8; - even_byte = 0; - in_sram_address += 2; - } - else - { - *value = temp & 0xff; - even_byte = 1; - } - } - sign_of_sequental_byte_read = 1; - return ERROR_OK; -} - -static int get_next_halfword_from_sram_buffer (struct target * target, - uint16_t * value) -{ - if (in_sram_address > MX3_NF_LAST_BUFFER_ADDR) - { - LOG_ERROR (sram_buffer_bounds_err_msg, in_sram_address); - *value = 0; - return ERROR_NAND_OPERATION_FAILED; - } - else - { - target_read_u16 (target, in_sram_address, value); - in_sram_address += 2; - } - return ERROR_OK; -} - -static int poll_for_complete_op (struct target * target, const char *text) -{ - uint16_t poll_complete_status; - for (int poll_cycle_count = 0; poll_cycle_count < 100; poll_cycle_count++) - { - usleep (25); - target_read_u16 (target, MX3_NF_CFG2, &poll_complete_status); - if (poll_complete_status & MX3_NF_BIT_OP_DONE) - { - break; - } - } - if (!(poll_complete_status & MX3_NF_BIT_OP_DONE)) - { - LOG_ERROR ("%s sending timeout", text); - return ERROR_NAND_OPERATION_FAILED; - } - return ERROR_OK; -} - -static int validate_target_state (struct nand_device *nand) -{ - struct mx3_nf_controller *mx3_nf_info = nand->controller_priv; - struct target *target = mx3_nf_info->target; - - if (target->state != TARGET_HALTED) - { - LOG_ERROR (target_not_halted_err_msg); - return ERROR_NAND_OPERATION_FAILED; - } - - if (mx3_nf_info->flags.target_little_endian != - (target->endianness == TARGET_LITTLE_ENDIAN)) - { - /* - * endianness changed after NAND controller probed - */ - return ERROR_NAND_OPERATION_FAILED; - } - return ERROR_OK; -} - -static int do_data_output (struct nand_device *nand) -{ - struct mx3_nf_controller *mx3_nf_info = nand->controller_priv; - struct target *target = mx3_nf_info->target; - switch (mx3_nf_info->fin) - { - case MX3_NF_FIN_DATAOUT: - /* - * start data output operation (set MX3_NF_BIT_OP_DONE==0) - */ - target_write_u16 (target, MX3_NF_CFG2, - MX3_NF_BIT_DATAOUT_TYPE (mx3_nf_info-> - optype)); - { - int poll_result; - poll_result = poll_for_complete_op (target, "data output"); - if (poll_result != ERROR_OK) - { - return poll_result; - } - } - mx3_nf_info->fin = MX3_NF_FIN_NONE; - /* - * ECC stuff - */ - if ((mx3_nf_info->optype == MX3_NF_DATAOUT_PAGE) - && mx3_nf_info->flags.hw_ecc_enabled) - { - uint16_t ecc_status; - target_read_u16 (target, MX3_NF_ECCSTATUS, &ecc_status); - switch (ecc_status & 0x000c) - { - case 1 << 2: - LOG_DEBUG - ("main area readed with 1 (correctable) error"); - break; - case 2 << 2: - LOG_DEBUG - ("main area readed with more than 1 (incorrectable) error"); - return ERROR_NAND_OPERATION_FAILED; - break; - } - switch (ecc_status & 0x0003) - { - case 1: - LOG_DEBUG - ("spare area readed with 1 (correctable) error"); - break; - case 2: - LOG_DEBUG - ("main area readed with more than 1 (incorrectable) error"); - return ERROR_NAND_OPERATION_FAILED; - break; - } - } - break; - case MX3_NF_FIN_NONE: - break; - } - return ERROR_OK; -} - -struct nand_flash_controller imx31_nand_flash_controller = { - .name = "imx31", - .nand_device_command = &imx31_nand_device_command, - .init = &imx31_init, - .reset = &imx31_reset, - .command = &imx31_command, - .address = &imx31_address, - .write_data = &imx31_write_data, - .read_data = &imx31_read_data, - .write_page = &imx31_write_page, - .read_page = &imx31_read_page, - .controller_ready = &imx31_controller_ready, - .nand_ready = &imx31_nand_ready, - }; diff --git a/src/flash/mx3_nand.h b/src/flash/mx3_nand.h deleted file mode 100644 index ddec92cf..00000000 --- a/src/flash/mx3_nand.h +++ /dev/null @@ -1,117 +0,0 @@ - -/*************************************************************************** - * Copyright (C) 2009 by Alexei Babich * - * Rezonans plc., Chelyabinsk, Russia * - * impatt@mail.ru * - * * - * 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. * - ***************************************************************************/ - -/* - * Freescale iMX3* OpenOCD NAND Flash controller support. - * - * Many thanks to Ben Dooks for writing s3c24xx driver. - */ -#include - -#define MX3_NF_BASE_ADDR 0xb8000000 -#define MX3_NF_BUFSIZ (MX3_NF_BASE_ADDR + 0xe00) -#define MX3_NF_BUFADDR (MX3_NF_BASE_ADDR + 0xe04) -#define MX3_NF_FADDR (MX3_NF_BASE_ADDR + 0xe06) -#define MX3_NF_FCMD (MX3_NF_BASE_ADDR + 0xe08) -#define MX3_NF_BUFCFG (MX3_NF_BASE_ADDR + 0xe0a) -#define MX3_NF_ECCSTATUS (MX3_NF_BASE_ADDR + 0xe0c) -#define MX3_NF_ECCMAINPOS (MX3_NF_BASE_ADDR + 0xe0e) -#define MX3_NF_ECCSPAREPOS (MX3_NF_BASE_ADDR + 0xe10) -#define MX3_NF_FWP (MX3_NF_BASE_ADDR + 0xe12) -#define MX3_NF_LOCKSTART (MX3_NF_BASE_ADDR + 0xe14) -#define MX3_NF_LOCKEND (MX3_NF_BASE_ADDR + 0xe16) -#define MX3_NF_FWPSTATUS (MX3_NF_BASE_ADDR + 0xe18) - /* - * all bits not marked as self-clearing bit - */ -#define MX3_NF_CFG1 (MX3_NF_BASE_ADDR + 0xe1a) -#define MX3_NF_CFG2 (MX3_NF_BASE_ADDR + 0xe1c) - -#define MX3_NF_MAIN_BUFFER0 (MX3_NF_BASE_ADDR + 0x0000) -#define MX3_NF_MAIN_BUFFER1 (MX3_NF_BASE_ADDR + 0x0200) -#define MX3_NF_MAIN_BUFFER2 (MX3_NF_BASE_ADDR + 0x0400) -#define MX3_NF_MAIN_BUFFER3 (MX3_NF_BASE_ADDR + 0x0600) -#define MX3_NF_SPARE_BUFFER0 (MX3_NF_BASE_ADDR + 0x0800) -#define MX3_NF_SPARE_BUFFER1 (MX3_NF_BASE_ADDR + 0x0810) -#define MX3_NF_SPARE_BUFFER2 (MX3_NF_BASE_ADDR + 0x0820) -#define MX3_NF_SPARE_BUFFER3 (MX3_NF_BASE_ADDR + 0x0830) -#define MX3_NF_MAIN_BUFFER_LEN 512 -#define MX3_NF_SPARE_BUFFER_LEN 16 -#define MX3_NF_LAST_BUFFER_ADDR ((MX3_NF_SPARE_BUFFER3) + MX3_NF_SPARE_BUFFER_LEN - 2) - -/* bits in MX3_NF_CFG1 register */ -#define MX3_NF_BIT_SPARE_ONLY_EN (1<<2) -#define MX3_NF_BIT_ECC_EN (1<<3) -#define MX3_NF_BIT_INT_DIS (1<<4) -#define MX3_NF_BIT_BE_EN (1<<5) -#define MX3_NF_BIT_RESET_EN (1<<6) -#define MX3_NF_BIT_FORCE_CE (1<<7) - -/* bits in MX3_NF_CFG2 register */ - -/*Flash Command Input*/ -#define MX3_NF_BIT_OP_FCI (1<<0) - /* - * Flash Address Input - */ -#define MX3_NF_BIT_OP_FAI (1<<1) - /* - * Flash Data Input - */ -#define MX3_NF_BIT_OP_FDI (1<<2) - -/* see "enum mx_dataout_type" below */ -#define MX3_NF_BIT_DATAOUT_TYPE(x) ((x)<<3) -#define MX3_NF_BIT_OP_DONE (1<<15) - -#define MX3_CCM_CGR2 0x53f80028 -#define MX3_GPR 0x43fac008 -#define MX3_PCSR 0x53f8000c - -enum mx_dataout_type -{ - MX3_NF_DATAOUT_PAGE = 1, - MX3_NF_DATAOUT_NANDID = 2, - MX3_NF_DATAOUT_NANDSTATUS = 4, -}; -enum mx_nf_finalize_action -{ - MX3_NF_FIN_NONE, - MX3_NF_FIN_DATAOUT, -}; - -struct mx3_nf_flags -{ - unsigned host_little_endian:1; - unsigned target_little_endian:1; - unsigned nand_readonly:1; - unsigned one_kb_sram:1; - unsigned hw_ecc_enabled:1; -}; - -struct mx3_nf_controller -{ - struct target *target; - enum mx_dataout_type optype; - enum mx_nf_finalize_action fin; - struct mx3_nf_flags flags; -}; diff --git a/src/flash/nand/Makefile.am b/src/flash/nand/Makefile.am new file mode 100644 index 00000000..e95717e2 --- /dev/null +++ b/src/flash/nand/Makefile.am @@ -0,0 +1,27 @@ +AM_CPPFLAGS = \ + -I$(top_srcdir)/src/flash \ + -I$(top_srcdir)/src/helper \ + -I$(top_srcdir)/src/jtag \ + -I$(top_srcdir)/src/target + +noinst_LTLIBRARIES = libocdflashnand.la + +libocdflashnand_la_SOURCES = \ + nonce.c \ + davinci.c \ + lpc3180.c \ + mx3.c \ + orion.c \ + s3c24xx.c \ + s3c2410.c \ + s3c2412.c \ + s3c2440.c \ + s3c2443.c + +noinst_HEADERS = \ + lpc3180.h \ + mx3.h \ + s3c24xx.h \ + s3c24xx_regs.h + +MAINTAINERCLEANFILES = $(srcdir)/Makefile.in diff --git a/src/flash/nand/davinci.c b/src/flash/nand/davinci.c new file mode 100644 index 00000000..72cd378a --- /dev/null +++ b/src/flash/nand/davinci.c @@ -0,0 +1,756 @@ +/*************************************************************************** + * 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, +}; diff --git a/src/flash/nand/lpc3180.c b/src/flash/nand/lpc3180.c new file mode 100644 index 00000000..031e6b1d --- /dev/null +++ b/src/flash/nand/lpc3180.c @@ -0,0 +1,910 @@ +/*************************************************************************** + * Copyright (C) 2007 by Dominic Rath * + * Dominic.Rath@gmx.de * + * * + * 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. * + ***************************************************************************/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "lpc3180.h" +#include "nand.h" + +static int lpc3180_reset(struct nand_device *nand); +static int lpc3180_controller_ready(struct nand_device *nand, int timeout); + +/* nand device lpc3180 + */ +NAND_DEVICE_COMMAND_HANDLER(lpc3180_nand_device_command) +{ + if (CMD_ARGC < 3) + { + LOG_WARNING("incomplete 'lpc3180' nand flash configuration"); + return ERROR_FLASH_BANK_INVALID; + } + + struct target *target = get_target(CMD_ARGV[1]); + if (NULL == target) + { + LOG_ERROR("target '%s' not defined", CMD_ARGV[1]); + return ERROR_NAND_DEVICE_INVALID; + } + + uint32_t osc_freq; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], osc_freq); + + struct lpc3180_nand_controller *lpc3180_info; + lpc3180_info = malloc(sizeof(struct lpc3180_nand_controller)); + nand->controller_priv = lpc3180_info; + + lpc3180_info->target = target; + lpc3180_info->osc_freq = osc_freq; + + if ((lpc3180_info->osc_freq < 1000) || (lpc3180_info->osc_freq > 20000)) + { + LOG_WARNING("LPC3180 oscillator frequency should be between 1000 and 20000 kHz, was %i", lpc3180_info->osc_freq); + } + lpc3180_info->selected_controller = LPC3180_NO_CONTROLLER; + lpc3180_info->sw_write_protection = 0; + lpc3180_info->sw_wp_lower_bound = 0x0; + lpc3180_info->sw_wp_upper_bound = 0x0; + + return ERROR_OK; +} + +static int lpc3180_pll(int fclkin, uint32_t pll_ctrl) +{ + int bypass = (pll_ctrl & 0x8000) >> 15; + int direct = (pll_ctrl & 0x4000) >> 14; + int feedback = (pll_ctrl & 0x2000) >> 13; + int p = (1 << ((pll_ctrl & 0x1800) >> 11) * 2); + int n = ((pll_ctrl & 0x0600) >> 9) + 1; + int m = ((pll_ctrl & 0x01fe) >> 1) + 1; + int lock = (pll_ctrl & 0x1); + + if (!lock) + LOG_WARNING("PLL is not locked"); + + if (!bypass && direct) /* direct mode */ + return (m * fclkin) / n; + + if (bypass && !direct) /* bypass mode */ + return fclkin / (2 * p); + + if (bypass & direct) /* direct bypass mode */ + return fclkin; + + if (feedback) /* integer mode */ + return m * (fclkin / n); + else /* non-integer mode */ + return (m / (2 * p)) * (fclkin / n); +} + +static float lpc3180_cycle_time(struct lpc3180_nand_controller *lpc3180_info) +{ + struct target *target = lpc3180_info->target; + uint32_t sysclk_ctrl, pwr_ctrl, hclkdiv_ctrl, hclkpll_ctrl; + int sysclk; + int hclk; + int hclk_pll; + float cycle; + + /* calculate timings */ + + /* determine current SYSCLK (13'MHz or main oscillator) */ + target_read_u32(target, 0x40004050, &sysclk_ctrl); + + if ((sysclk_ctrl & 1) == 0) + sysclk = lpc3180_info->osc_freq; + else + sysclk = 13000; + + /* determine selected HCLK source */ + target_read_u32(target, 0x40004044, &pwr_ctrl); + + if ((pwr_ctrl & (1 << 2)) == 0) /* DIRECT RUN mode */ + { + hclk = sysclk; + } + else + { + target_read_u32(target, 0x40004058, &hclkpll_ctrl); + hclk_pll = lpc3180_pll(sysclk, hclkpll_ctrl); + + target_read_u32(target, 0x40004040, &hclkdiv_ctrl); + + if (pwr_ctrl & (1 << 10)) /* ARM_CLK and HCLK use PERIPH_CLK */ + { + hclk = hclk_pll / (((hclkdiv_ctrl & 0x7c) >> 2) + 1); + } + else /* HCLK uses HCLK_PLL */ + { + hclk = hclk_pll / (1 << (hclkdiv_ctrl & 0x3)); + } + } + + LOG_DEBUG("LPC3180 HCLK currently clocked at %i kHz", hclk); + + cycle = (1.0 / hclk) * 1000000.0; + + return cycle; +} + +static int lpc3180_init(struct nand_device *nand) +{ + struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv; + struct target *target = lpc3180_info->target; + int bus_width = nand->bus_width ? : 8; + int address_cycles = nand->address_cycles ? : 3; + int page_size = nand->page_size ? : 512; + + if (target->state != TARGET_HALTED) + { + LOG_ERROR("target must be halted to use LPC3180 NAND flash controller"); + return ERROR_NAND_OPERATION_FAILED; + } + + /* sanitize arguments */ + if ((bus_width != 8) && (bus_width != 16)) + { + LOG_ERROR("LPC3180 only supports 8 or 16 bit bus width, not %i", bus_width); + return ERROR_NAND_OPERATION_NOT_SUPPORTED; + } + + /* The LPC3180 only brings out 8 bit NAND data bus, but the controller + * would support 16 bit, too, so we just warn about this for now + */ + if (bus_width == 16) + { + LOG_WARNING("LPC3180 only supports 8 bit bus width"); + } + + /* inform calling code about selected bus width */ + nand->bus_width = bus_width; + + if ((address_cycles != 3) && (address_cycles != 4)) + { + LOG_ERROR("LPC3180 only supports 3 or 4 address cycles, not %i", address_cycles); + return ERROR_NAND_OPERATION_NOT_SUPPORTED; + } + + if ((page_size != 512) && (page_size != 2048)) + { + LOG_ERROR("LPC3180 only supports 512 or 2048 byte pages, not %i", page_size); + return ERROR_NAND_OPERATION_NOT_SUPPORTED; + } + + /* select MLC controller if none is currently selected */ + if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER) + { + LOG_DEBUG("no LPC3180 NAND flash controller selected, using default 'mlc'"); + lpc3180_info->selected_controller = LPC3180_MLC_CONTROLLER; + } + + if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER) + { + uint32_t mlc_icr_value = 0x0; + float cycle; + int twp, twh, trp, treh, trhz, trbwb, tcea; + + /* FLASHCLK_CTRL = 0x22 (enable clock for MLC flash controller) */ + target_write_u32(target, 0x400040c8, 0x22); + + /* MLC_CEH = 0x0 (Force nCE assert) */ + target_write_u32(target, 0x200b804c, 0x0); + + /* MLC_LOCK = 0xa25e (unlock protected registers) */ + target_write_u32(target, 0x200b8044, 0xa25e); + + /* MLC_ICR = configuration */ + if (lpc3180_info->sw_write_protection) + mlc_icr_value |= 0x8; + if (page_size == 2048) + mlc_icr_value |= 0x4; + if (address_cycles == 4) + mlc_icr_value |= 0x2; + if (bus_width == 16) + mlc_icr_value |= 0x1; + target_write_u32(target, 0x200b8030, mlc_icr_value); + + /* calculate NAND controller timings */ + cycle = lpc3180_cycle_time(lpc3180_info); + + twp = ((40 / cycle) + 1); + twh = ((20 / cycle) + 1); + trp = ((30 / cycle) + 1); + treh = ((15 / cycle) + 1); + trhz = ((30 / cycle) + 1); + trbwb = ((100 / cycle) + 1); + tcea = ((45 / cycle) + 1); + + /* MLC_LOCK = 0xa25e (unlock protected registers) */ + target_write_u32(target, 0x200b8044, 0xa25e); + + /* MLC_TIME_REG */ + target_write_u32(target, 0x200b8034, (twp & 0xf) | ((twh & 0xf) << 4) | + ((trp & 0xf) << 8) | ((treh & 0xf) << 12) | ((trhz & 0x7) << 16) | + ((trbwb & 0x1f) << 19) | ((tcea & 0x3) << 24)); + + lpc3180_reset(nand); + } + else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER) + { + float cycle; + int r_setup, r_hold, r_width, r_rdy; + int w_setup, w_hold, w_width, w_rdy; + + /* FLASHCLK_CTRL = 0x05 (enable clock for SLC flash controller) */ + target_write_u32(target, 0x400040c8, 0x05); + + /* SLC_CFG = 0x (Force nCE assert, ECC enabled, WIDTH = bus_width) */ + target_write_u32(target, 0x20020014, 0x28 | (bus_width == 16) ? 1 : 0); + + /* calculate NAND controller timings */ + cycle = lpc3180_cycle_time(lpc3180_info); + + r_setup = w_setup = 0; + r_hold = w_hold = 10 / cycle; + r_width = 30 / cycle; + w_width = 40 / cycle; + r_rdy = w_rdy = 100 / cycle; + + /* SLC_TAC: SLC timing arcs register */ + target_write_u32(target, 0x2002002c, (r_setup & 0xf) | ((r_hold & 0xf) << 4) | + ((r_width & 0xf) << 8) | ((r_rdy & 0xf) << 12) | ((w_setup & 0xf) << 16) | + ((w_hold & 0xf) << 20) | ((w_width & 0xf) << 24) | ((w_rdy & 0xf) << 28)); + + lpc3180_reset(nand); + } + + return ERROR_OK; +} + +static int lpc3180_reset(struct nand_device *nand) +{ + struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv; + struct target *target = lpc3180_info->target; + + if (target->state != TARGET_HALTED) + { + LOG_ERROR("target must be halted to use LPC3180 NAND flash controller"); + return ERROR_NAND_OPERATION_FAILED; + } + + if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER) + { + LOG_ERROR("BUG: no LPC3180 NAND flash controller selected"); + return ERROR_NAND_OPERATION_FAILED; + } + else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER) + { + /* MLC_CMD = 0xff (reset controller and NAND device) */ + target_write_u32(target, 0x200b8000, 0xff); + + if (!lpc3180_controller_ready(nand, 100)) + { + LOG_ERROR("LPC3180 NAND controller timed out after reset"); + return ERROR_NAND_OPERATION_TIMEOUT; + } + } + else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER) + { + /* SLC_CTRL = 0x6 (ECC_CLEAR, SW_RESET) */ + target_write_u32(target, 0x20020010, 0x6); + + if (!lpc3180_controller_ready(nand, 100)) + { + LOG_ERROR("LPC3180 NAND controller timed out after reset"); + return ERROR_NAND_OPERATION_TIMEOUT; + } + } + + return ERROR_OK; +} + +static int lpc3180_command(struct nand_device *nand, uint8_t command) +{ + struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv; + struct target *target = lpc3180_info->target; + + if (target->state != TARGET_HALTED) + { + LOG_ERROR("target must be halted to use LPC3180 NAND flash controller"); + return ERROR_NAND_OPERATION_FAILED; + } + + if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER) + { + LOG_ERROR("BUG: no LPC3180 NAND flash controller selected"); + return ERROR_NAND_OPERATION_FAILED; + } + else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER) + { + /* MLC_CMD = command */ + target_write_u32(target, 0x200b8000, command); + } + else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER) + { + /* SLC_CMD = command */ + target_write_u32(target, 0x20020008, command); + } + + return ERROR_OK; +} + +static int lpc3180_address(struct nand_device *nand, uint8_t address) +{ + struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv; + struct target *target = lpc3180_info->target; + + if (target->state != TARGET_HALTED) + { + LOG_ERROR("target must be halted to use LPC3180 NAND flash controller"); + return ERROR_NAND_OPERATION_FAILED; + } + + if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER) + { + LOG_ERROR("BUG: no LPC3180 NAND flash controller selected"); + return ERROR_NAND_OPERATION_FAILED; + } + else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER) + { + /* MLC_ADDR = address */ + target_write_u32(target, 0x200b8004, address); + } + else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER) + { + /* SLC_ADDR = address */ + target_write_u32(target, 0x20020004, address); + } + + return ERROR_OK; +} + +static int lpc3180_write_data(struct nand_device *nand, uint16_t data) +{ + struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv; + struct target *target = lpc3180_info->target; + + if (target->state != TARGET_HALTED) + { + LOG_ERROR("target must be halted to use LPC3180 NAND flash controller"); + return ERROR_NAND_OPERATION_FAILED; + } + + if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER) + { + LOG_ERROR("BUG: no LPC3180 NAND flash controller selected"); + return ERROR_NAND_OPERATION_FAILED; + } + else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER) + { + /* MLC_DATA = data */ + target_write_u32(target, 0x200b0000, data); + } + else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER) + { + /* SLC_DATA = data */ + target_write_u32(target, 0x20020000, data); + } + + return ERROR_OK; +} + +static int lpc3180_read_data(struct nand_device *nand, void *data) +{ + struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv; + struct target *target = lpc3180_info->target; + + if (target->state != TARGET_HALTED) + { + LOG_ERROR("target must be halted to use LPC3180 NAND flash controller"); + return ERROR_NAND_OPERATION_FAILED; + } + + if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER) + { + LOG_ERROR("BUG: no LPC3180 NAND flash controller selected"); + return ERROR_NAND_OPERATION_FAILED; + } + else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER) + { + /* data = MLC_DATA, use sized access */ + if (nand->bus_width == 8) + { + uint8_t *data8 = data; + target_read_u8(target, 0x200b0000, data8); + } + else if (nand->bus_width == 16) + { + uint16_t *data16 = data; + target_read_u16(target, 0x200b0000, data16); + } + else + { + LOG_ERROR("BUG: bus_width neither 8 nor 16 bit"); + return ERROR_NAND_OPERATION_FAILED; + } + } + else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER) + { + uint32_t data32; + + /* data = SLC_DATA, must use 32-bit access */ + target_read_u32(target, 0x20020000, &data32); + + if (nand->bus_width == 8) + { + uint8_t *data8 = data; + *data8 = data32 & 0xff; + } + else if (nand->bus_width == 16) + { + uint16_t *data16 = data; + *data16 = data32 & 0xffff; + } + else + { + LOG_ERROR("BUG: bus_width neither 8 nor 16 bit"); + return ERROR_NAND_OPERATION_FAILED; + } + } + + return ERROR_OK; +} + +static int lpc3180_write_page(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) +{ + struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv; + struct target *target = lpc3180_info->target; + int retval; + uint8_t status; + + if (target->state != TARGET_HALTED) + { + LOG_ERROR("target must be halted to use LPC3180 NAND flash controller"); + return ERROR_NAND_OPERATION_FAILED; + } + + if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER) + { + LOG_ERROR("BUG: no LPC3180 NAND flash controller selected"); + return ERROR_NAND_OPERATION_FAILED; + } + else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER) + { + uint8_t *page_buffer; + uint8_t *oob_buffer; + int quarter, num_quarters; + + if (!data && oob) + { + LOG_ERROR("LPC3180 MLC controller can't write OOB data only"); + return ERROR_NAND_OPERATION_NOT_SUPPORTED; + } + + if (oob && (oob_size > 6)) + { + LOG_ERROR("LPC3180 MLC controller can't write more than 6 bytes of OOB data"); + return ERROR_NAND_OPERATION_NOT_SUPPORTED; + } + + if (data_size > (uint32_t)nand->page_size) + { + LOG_ERROR("data size exceeds page size"); + return ERROR_NAND_OPERATION_NOT_SUPPORTED; + } + + /* MLC_CMD = sequential input */ + target_write_u32(target, 0x200b8000, NAND_CMD_SEQIN); + + page_buffer = malloc(512); + oob_buffer = malloc(6); + + if (nand->page_size == 512) + { + /* MLC_ADDR = 0x0 (one column cycle) */ + target_write_u32(target, 0x200b8004, 0x0); + + /* MLC_ADDR = row */ + target_write_u32(target, 0x200b8004, page & 0xff); + target_write_u32(target, 0x200b8004, (page >> 8) & 0xff); + + if (nand->address_cycles == 4) + target_write_u32(target, 0x200b8004, (page >> 16) & 0xff); + } + else + { + /* MLC_ADDR = 0x0 (two column cycles) */ + target_write_u32(target, 0x200b8004, 0x0); + target_write_u32(target, 0x200b8004, 0x0); + + /* MLC_ADDR = row */ + target_write_u32(target, 0x200b8004, page & 0xff); + target_write_u32(target, 0x200b8004, (page >> 8) & 0xff); + } + + /* when using the MLC controller, we have to treat a large page device + * as being made out of four quarters, each the size of a small page device + */ + num_quarters = (nand->page_size == 2048) ? 4 : 1; + + for (quarter = 0; quarter < num_quarters; quarter++) + { + int thisrun_data_size = (data_size > 512) ? 512 : data_size; + int thisrun_oob_size = (oob_size > 6) ? 6 : oob_size; + + memset(page_buffer, 0xff, 512); + if (data) + { + memcpy(page_buffer, data, thisrun_data_size); + data_size -= thisrun_data_size; + data += thisrun_data_size; + } + + memset(oob_buffer, 0xff, (nand->page_size == 512) ? 6 : 24); + if (oob) + { + memcpy(page_buffer, oob, thisrun_oob_size); + oob_size -= thisrun_oob_size; + oob += thisrun_oob_size; + } + + /* write MLC_ECC_ENC_REG to start encode cycle */ + target_write_u32(target, 0x200b8008, 0x0); + + target_write_memory(target, 0x200a8000, 4, 128, page_buffer + (quarter * 512)); + target_write_memory(target, 0x200a8000, 1, 6, oob_buffer + (quarter * 6)); + + /* write MLC_ECC_AUTO_ENC_REG to start auto encode */ + target_write_u32(target, 0x200b8010, 0x0); + + if (!lpc3180_controller_ready(nand, 1000)) + { + LOG_ERROR("timeout while waiting for completion of auto encode cycle"); + return ERROR_NAND_OPERATION_FAILED; + } + } + + /* MLC_CMD = auto program command */ + target_write_u32(target, 0x200b8000, NAND_CMD_PAGEPROG); + + if ((retval = 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 didn't pass, status: 0x%2.2x", status); + return ERROR_NAND_OPERATION_FAILED; + } + + free(page_buffer); + free(oob_buffer); + } + else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER) + { + return nand_write_page_raw(nand, page, data, data_size, oob, oob_size); + } + + return ERROR_OK; +} + +static int lpc3180_read_page(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) +{ + struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv; + struct target *target = lpc3180_info->target; + + if (target->state != TARGET_HALTED) + { + LOG_ERROR("target must be halted to use LPC3180 NAND flash controller"); + return ERROR_NAND_OPERATION_FAILED; + } + + if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER) + { + LOG_ERROR("BUG: no LPC3180 NAND flash controller selected"); + return ERROR_NAND_OPERATION_FAILED; + } + else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER) + { + uint8_t *page_buffer; + uint8_t *oob_buffer; + uint32_t page_bytes_done = 0; + uint32_t oob_bytes_done = 0; + uint32_t mlc_isr; + +#if 0 + if (oob && (oob_size > 6)) + { + LOG_ERROR("LPC3180 MLC controller can't read more than 6 bytes of OOB data"); + return ERROR_NAND_OPERATION_NOT_SUPPORTED; + } +#endif + + if (data_size > (uint32_t)nand->page_size) + { + LOG_ERROR("data size exceeds page size"); + return ERROR_NAND_OPERATION_NOT_SUPPORTED; + } + + if (nand->page_size == 2048) + { + page_buffer = malloc(2048); + oob_buffer = malloc(64); + } + else + { + page_buffer = malloc(512); + oob_buffer = malloc(16); + } + + if (!data && oob) + { + /* MLC_CMD = Read OOB + * we can use the READOOB command on both small and large page devices, + * as the controller translates the 0x50 command to a 0x0 with appropriate + * positioning of the serial buffer read pointer + */ + target_write_u32(target, 0x200b8000, NAND_CMD_READOOB); + } + else + { + /* MLC_CMD = Read0 */ + target_write_u32(target, 0x200b8000, NAND_CMD_READ0); + } + + if (nand->page_size == 512) + { + /* small page device */ + /* MLC_ADDR = 0x0 (one column cycle) */ + target_write_u32(target, 0x200b8004, 0x0); + + /* MLC_ADDR = row */ + target_write_u32(target, 0x200b8004, page & 0xff); + target_write_u32(target, 0x200b8004, (page >> 8) & 0xff); + + if (nand->address_cycles == 4) + target_write_u32(target, 0x200b8004, (page >> 16) & 0xff); + } + else + { + /* large page device */ + /* MLC_ADDR = 0x0 (two column cycles) */ + target_write_u32(target, 0x200b8004, 0x0); + target_write_u32(target, 0x200b8004, 0x0); + + /* MLC_ADDR = row */ + target_write_u32(target, 0x200b8004, page & 0xff); + target_write_u32(target, 0x200b8004, (page >> 8) & 0xff); + + /* MLC_CMD = Read Start */ + target_write_u32(target, 0x200b8000, NAND_CMD_READSTART); + } + + while (page_bytes_done < (uint32_t)nand->page_size) + { + /* MLC_ECC_AUTO_DEC_REG = dummy */ + target_write_u32(target, 0x200b8014, 0xaa55aa55); + + if (!lpc3180_controller_ready(nand, 1000)) + { + LOG_ERROR("timeout while waiting for completion of auto decode cycle"); + return ERROR_NAND_OPERATION_FAILED; + } + + target_read_u32(target, 0x200b8048, &mlc_isr); + + if (mlc_isr & 0x8) + { + if (mlc_isr & 0x40) + { + LOG_ERROR("uncorrectable error detected: 0x%2.2x", (unsigned)mlc_isr); + return ERROR_NAND_OPERATION_FAILED; + } + + LOG_WARNING("%i symbol error detected and corrected", ((int)(((mlc_isr & 0x30) >> 4) + 1))); + } + + if (data) + { + target_read_memory(target, 0x200a8000, 4, 128, page_buffer + page_bytes_done); + } + + if (oob) + { + target_read_memory(target, 0x200a8000, 4, 4, oob_buffer + oob_bytes_done); + } + + page_bytes_done += 512; + oob_bytes_done += 16; + } + + if (data) + memcpy(data, page_buffer, data_size); + + if (oob) + memcpy(oob, oob_buffer, oob_size); + + free(page_buffer); + free(oob_buffer); + } + else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER) + { + return nand_read_page_raw(nand, page, data, data_size, oob, oob_size); + } + + return ERROR_OK; +} + +static int lpc3180_controller_ready(struct nand_device *nand, int timeout) +{ + struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv; + struct target *target = lpc3180_info->target; + uint8_t status = 0x0; + + if (target->state != TARGET_HALTED) + { + LOG_ERROR("target must be halted to use LPC3180 NAND flash controller"); + return ERROR_NAND_OPERATION_FAILED; + } + + do + { + if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER) + { + /* Read MLC_ISR, wait for controller to become ready */ + target_read_u8(target, 0x200b8048, &status); + + if (status & 2) + return 1; + } + else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER) + { + /* we pretend that the SLC controller is always ready */ + return 1; + } + + alive_sleep(1); + } while (timeout-- > 0); + + return 0; +} + +static int lpc3180_nand_ready(struct nand_device *nand, int timeout) +{ + struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv; + struct target *target = lpc3180_info->target; + + if (target->state != TARGET_HALTED) + { + LOG_ERROR("target must be halted to use LPC3180 NAND flash controller"); + return ERROR_NAND_OPERATION_FAILED; + } + + do + { + if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER) + { + uint8_t status = 0x0; + + /* Read MLC_ISR, wait for NAND flash device to become ready */ + target_read_u8(target, 0x200b8048, &status); + + if (status & 1) + return 1; + } + else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER) + { + uint32_t status = 0x0; + + /* Read SLC_STAT and check READY bit */ + target_read_u32(target, 0x20020018, &status); + + if (status & 1) + return 1; + } + + alive_sleep(1); + } while (timeout-- > 0); + + return 0; +} + +COMMAND_HANDLER(handle_lpc3180_select_command) +{ + struct lpc3180_nand_controller *lpc3180_info = NULL; + char *selected[] = + { + "no", "mlc", "slc" + }; + + if ((CMD_ARGC < 1) || (CMD_ARGC > 2)) + { + return ERROR_COMMAND_SYNTAX_ERROR; + } + + unsigned num; + COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], num); + struct nand_device *nand = get_nand_device_by_num(num); + if (!nand) + { + command_print(CMD_CTX, "nand device '#%s' is out of bounds", CMD_ARGV[0]); + return ERROR_OK; + } + + lpc3180_info = nand->controller_priv; + + if (CMD_ARGC == 2) + { + if (strcmp(CMD_ARGV[1], "mlc") == 0) + { + lpc3180_info->selected_controller = LPC3180_MLC_CONTROLLER; + } + else if (strcmp(CMD_ARGV[1], "slc") == 0) + { + lpc3180_info->selected_controller = LPC3180_SLC_CONTROLLER; + } + else + { + return ERROR_COMMAND_SYNTAX_ERROR; + } + } + + command_print(CMD_CTX, "%s controller selected", selected[lpc3180_info->selected_controller]); + + return ERROR_OK; +} + +static const struct command_registration lpc3180_exec_command_handlers[] = { + { + .name = "select", + .handler = &handle_lpc3180_select_command, + .mode = COMMAND_EXEC, + .help = "select <'mlc'|'slc'> controller (default is mlc)", + .usage = " (mlc|slc)", + }, + COMMAND_REGISTRATION_DONE +}; +static const struct command_registration lpc3180_command_handler[] = { + { + .name = "lpc3180", + .mode = COMMAND_ANY, + .help = "LPC3180 NAND flash controller commands", + .chain = lpc3180_exec_command_handlers, + }, + COMMAND_REGISTRATION_DONE +}; + +struct nand_flash_controller lpc3180_nand_controller = { + .name = "lpc3180", + .commands = lpc3180_command_handler, + .nand_device_command = lpc3180_nand_device_command, + .init = lpc3180_init, + .reset = lpc3180_reset, + .command = lpc3180_command, + .address = lpc3180_address, + .write_data = lpc3180_write_data, + .read_data = lpc3180_read_data, + .write_page = lpc3180_write_page, + .read_page = lpc3180_read_page, + .controller_ready = lpc3180_controller_ready, + .nand_ready = lpc3180_nand_ready, + }; diff --git a/src/flash/nand/lpc3180.h b/src/flash/nand/lpc3180.h new file mode 100644 index 00000000..0891cedf --- /dev/null +++ b/src/flash/nand/lpc3180.h @@ -0,0 +1,40 @@ +/*************************************************************************** + * Copyright (C) 2007 by Dominic Rath * + * Dominic.Rath@gmx.de * + * * + * 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. * + ***************************************************************************/ +#ifndef LPC3180_NAND_CONTROLLER_H +#define LPC3180_NAND_CONTROLLER_H + +enum lpc3180_selected_controller +{ + LPC3180_NO_CONTROLLER, + LPC3180_MLC_CONTROLLER, + LPC3180_SLC_CONTROLLER, +}; + +struct lpc3180_nand_controller +{ + struct target *target; + int osc_freq; + enum lpc3180_selected_controller selected_controller; + int sw_write_protection; + uint32_t sw_wp_lower_bound; + uint32_t sw_wp_upper_bound; +}; + +#endif /*LPC3180_NAND_CONTROLLER_H */ diff --git a/src/flash/nand/mx3.c b/src/flash/nand/mx3.c new file mode 100644 index 00000000..21577a6e --- /dev/null +++ b/src/flash/nand/mx3.c @@ -0,0 +1,879 @@ + +/*************************************************************************** + * Copyright (C) 2009 by Alexei Babich * + * Rezonans plc., Chelyabinsk, Russia * + * impatt@mail.ru * + * * + * 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. * + ***************************************************************************/ + +/* + * Freescale iMX3* OpenOCD NAND Flash controller support. + * + * Many thanks to Ben Dooks for writing s3c24xx driver. + */ + +/* +driver tested with STMicro NAND512W3A @imx31 +tested "nand probe #", "nand erase # 0 #", "nand dump # file 0 #", "nand write # file 0" +get_next_halfword_from_sram_buffer() not tested +*/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "mx3.h" + +static const char target_not_halted_err_msg[] = + "target must be halted to use mx3 NAND flash controller"; +static const char data_block_size_err_msg[] = + "minimal granularity is one half-word, %" PRId32 " is incorrect"; +static const char sram_buffer_bounds_err_msg[] = + "trying to access out of SRAM buffer bound (addr=0x%" PRIx32 ")"; +static const char get_status_register_err_msg[] = "can't get NAND status"; +static uint32_t in_sram_address; +unsigned char sign_of_sequental_byte_read; + +static int test_iomux_settings (struct target * target, uint32_t value, + uint32_t mask, const char *text); +static int initialize_nf_controller (struct nand_device *nand); +static int get_next_byte_from_sram_buffer (struct target * target, uint8_t * value); +static int get_next_halfword_from_sram_buffer (struct target * target, + uint16_t * value); +static int poll_for_complete_op (struct target * target, const char *text); +static int validate_target_state (struct nand_device *nand); +static int do_data_output (struct nand_device *nand); + +static int imx31_command (struct nand_device *nand, uint8_t command); +static int imx31_address (struct nand_device *nand, uint8_t address); +static int imx31_controller_ready (struct nand_device *nand, int tout); + +NAND_DEVICE_COMMAND_HANDLER(imx31_nand_device_command) +{ + struct mx3_nf_controller *mx3_nf_info; + mx3_nf_info = malloc (sizeof (struct mx3_nf_controller)); + if (mx3_nf_info == NULL) + { + LOG_ERROR ("no memory for nand controller"); + return ERROR_FAIL; + } + + nand->controller_priv = mx3_nf_info; + + mx3_nf_info->target = get_target (CMD_ARGV[1]); + if (mx3_nf_info->target == NULL) + { + LOG_ERROR ("target '%s' not defined", CMD_ARGV[1]); + return ERROR_FAIL; + } + if (CMD_ARGC < 3) + { + LOG_ERROR ("use \"nand device imx31 target noecc|hwecc\""); + return ERROR_FAIL; + } + /* + * check hwecc requirements + */ + { + int hwecc_needed; + hwecc_needed = strcmp (CMD_ARGV[2], "hwecc"); + if (hwecc_needed == 0) + { + mx3_nf_info->flags.hw_ecc_enabled = 1; + } + else + { + mx3_nf_info->flags.hw_ecc_enabled = 0; + } + } + + mx3_nf_info->optype = MX3_NF_DATAOUT_PAGE; + mx3_nf_info->fin = MX3_NF_FIN_NONE; + mx3_nf_info->flags.target_little_endian = + (mx3_nf_info->target->endianness == TARGET_LITTLE_ENDIAN); + /* + * testing host endianess + */ + { + int x = 1; + if (*(char *) &x == 1) + { + mx3_nf_info->flags.host_little_endian = 1; + } + else + { + mx3_nf_info->flags.host_little_endian = 0; + } + } + return ERROR_OK; +} + +static int imx31_init (struct nand_device *nand) +{ + struct mx3_nf_controller *mx3_nf_info = nand->controller_priv; + struct target *target = mx3_nf_info->target; + + { + /* + * validate target state + */ + int validate_target_result; + validate_target_result = validate_target_state(nand); + if (validate_target_result != ERROR_OK) + { + return validate_target_result; + } + } + + { + uint16_t buffsize_register_content; + target_read_u16 (target, MX3_NF_BUFSIZ, &buffsize_register_content); + mx3_nf_info->flags.one_kb_sram = !(buffsize_register_content & 0x000f); + } + + { + uint32_t pcsr_register_content; + target_read_u32 (target, MX3_PCSR, &pcsr_register_content); + if (!nand->bus_width) + { + nand->bus_width = + (pcsr_register_content & 0x80000000) ? 16 : 8; + } + else + { + pcsr_register_content |= + ((nand->bus_width == 16) ? 0x80000000 : 0x00000000); + target_write_u32 (target, MX3_PCSR, pcsr_register_content); + } + + if (!nand->page_size) + { + nand->page_size = + (pcsr_register_content & 0x40000000) ? 2048 : 512; + } + else + { + pcsr_register_content |= + ((nand->page_size == 2048) ? 0x40000000 : 0x00000000); + target_write_u32 (target, MX3_PCSR, pcsr_register_content); + } + if (mx3_nf_info->flags.one_kb_sram && (nand->page_size == 2048)) + { + LOG_ERROR + ("NAND controller have only 1 kb SRAM, so pagesize 2048 is incompatible with it"); + } + } + + { + uint32_t cgr_register_content; + target_read_u32 (target, MX3_CCM_CGR2, &cgr_register_content); + if (!(cgr_register_content & 0x00000300)) + { + LOG_ERROR ("clock gating to EMI disabled"); + return ERROR_FAIL; + } + } + + { + uint32_t gpr_register_content; + target_read_u32 (target, MX3_GPR, &gpr_register_content); + if (gpr_register_content & 0x00000060) + { + LOG_ERROR ("pins mode overrided by GPR"); + return ERROR_FAIL; + } + } + + { + /* + * testing IOMUX settings; must be in "functional-mode output and + * functional-mode input" mode + */ + int test_iomux; + test_iomux = ERROR_OK; + test_iomux |= + test_iomux_settings (target, 0x43fac0c0, 0x7f7f7f00, "d0,d1,d2"); + test_iomux |= + test_iomux_settings (target, 0x43fac0c4, 0x7f7f7f7f, "d3,d4,d5,d6"); + test_iomux |= + test_iomux_settings (target, 0x43fac0c8, 0x0000007f, "d7"); + if (nand->bus_width == 16) + { + test_iomux |= + test_iomux_settings (target, 0x43fac0c8, 0x7f7f7f00, + "d8,d9,d10"); + test_iomux |= + test_iomux_settings (target, 0x43fac0cc, 0x7f7f7f7f, + "d11,d12,d13,d14"); + test_iomux |= + test_iomux_settings (target, 0x43fac0d0, 0x0000007f, "d15"); + } + test_iomux |= + test_iomux_settings (target, 0x43fac0d0, 0x7f7f7f00, + "nfwp,nfce,nfrb"); + test_iomux |= + test_iomux_settings (target, 0x43fac0d4, 0x7f7f7f7f, + "nfwe,nfre,nfale,nfcle"); + if (test_iomux != ERROR_OK) + { + return ERROR_FAIL; + } + } + + initialize_nf_controller (nand); + + { + int retval; + uint16_t nand_status_content; + retval = ERROR_OK; + retval |= imx31_command (nand, NAND_CMD_STATUS); + retval |= imx31_address (nand, 0x00); + retval |= do_data_output (nand); + if (retval != ERROR_OK) + { + LOG_ERROR (get_status_register_err_msg); + return ERROR_FAIL; + } + target_read_u16 (target, MX3_NF_MAIN_BUFFER0, &nand_status_content); + if (!(nand_status_content & 0x0080)) + { + /* + * is host-big-endian correctly ?? + */ + LOG_INFO ("NAND read-only"); + mx3_nf_info->flags.nand_readonly = 1; + } + else + { + mx3_nf_info->flags.nand_readonly = 0; + } + } + return ERROR_OK; +} + +static int imx31_read_data (struct nand_device *nand, void *data) +{ + struct mx3_nf_controller *mx3_nf_info = nand->controller_priv; + struct target *target = mx3_nf_info->target; + { + /* + * validate target state + */ + int validate_target_result; + validate_target_result = validate_target_state (nand); + if (validate_target_result != ERROR_OK) + { + return validate_target_result; + } + } + + { + /* + * get data from nand chip + */ + int try_data_output_from_nand_chip; + try_data_output_from_nand_chip = do_data_output (nand); + if (try_data_output_from_nand_chip != ERROR_OK) + { + return try_data_output_from_nand_chip; + } + } + + if (nand->bus_width == 16) + { + get_next_halfword_from_sram_buffer (target, data); + } + else + { + get_next_byte_from_sram_buffer (target, data); + } + + return ERROR_OK; +} + +static int imx31_write_data (struct nand_device *nand, uint16_t data) +{ + LOG_ERROR ("write_data() not implemented"); + return ERROR_NAND_OPERATION_FAILED; +} + +static int imx31_nand_ready (struct nand_device *nand, int timeout) +{ + return imx31_controller_ready (nand, timeout); +} + +static int imx31_reset (struct nand_device *nand) +{ + /* + * validate target state + */ + int validate_target_result; + validate_target_result = validate_target_state (nand); + if (validate_target_result != ERROR_OK) + { + return validate_target_result; + } + initialize_nf_controller (nand); + return ERROR_OK; +} + +static int imx31_command (struct nand_device *nand, uint8_t command) +{ + struct mx3_nf_controller *mx3_nf_info = nand->controller_priv; + struct target *target = mx3_nf_info->target; + { + /* + * validate target state + */ + int validate_target_result; + validate_target_result = validate_target_state (nand); + if (validate_target_result != ERROR_OK) + { + return validate_target_result; + } + } + + switch (command) + { + case NAND_CMD_READOOB: + command = NAND_CMD_READ0; + in_sram_address = MX3_NF_SPARE_BUFFER0; /* set read point for + * data_read() and + * read_block_data() to + * spare area in SRAM + * buffer */ + break; + case NAND_CMD_READ1: + command = NAND_CMD_READ0; + /* + * offset == one half of page size + */ + in_sram_address = + MX3_NF_MAIN_BUFFER0 + (nand->page_size >> 1); + default: + in_sram_address = MX3_NF_MAIN_BUFFER0; + } + + target_write_u16 (target, MX3_NF_FCMD, command); + /* + * start command input operation (set MX3_NF_BIT_OP_DONE==0) + */ + target_write_u16 (target, MX3_NF_CFG2, MX3_NF_BIT_OP_FCI); + { + int poll_result; + poll_result = poll_for_complete_op (target, "command"); + if (poll_result != ERROR_OK) + { + return poll_result; + } + } + /* + * reset cursor to begin of the buffer + */ + sign_of_sequental_byte_read = 0; + switch (command) + { + case NAND_CMD_READID: + mx3_nf_info->optype = MX3_NF_DATAOUT_NANDID; + mx3_nf_info->fin = MX3_NF_FIN_DATAOUT; + break; + case NAND_CMD_STATUS: + mx3_nf_info->optype = MX3_NF_DATAOUT_NANDSTATUS; + mx3_nf_info->fin = MX3_NF_FIN_DATAOUT; + break; + case NAND_CMD_READ0: + mx3_nf_info->fin = MX3_NF_FIN_DATAOUT; + mx3_nf_info->optype = MX3_NF_DATAOUT_PAGE; + break; + default: + mx3_nf_info->optype = MX3_NF_DATAOUT_PAGE; + } + return ERROR_OK; +} + +static int imx31_address (struct nand_device *nand, uint8_t address) +{ + struct mx3_nf_controller *mx3_nf_info = nand->controller_priv; + struct target *target = mx3_nf_info->target; + { + /* + * validate target state + */ + int validate_target_result; + validate_target_result = validate_target_state (nand); + if (validate_target_result != ERROR_OK) + { + return validate_target_result; + } + } + + target_write_u16 (target, MX3_NF_FADDR, address); + /* + * start address input operation (set MX3_NF_BIT_OP_DONE==0) + */ + target_write_u16 (target, MX3_NF_CFG2, MX3_NF_BIT_OP_FAI); + { + int poll_result; + poll_result = poll_for_complete_op (target, "address"); + if (poll_result != ERROR_OK) + { + return poll_result; + } + } + return ERROR_OK; +} + +static int imx31_controller_ready (struct nand_device *nand, int tout) +{ + uint16_t poll_complete_status; + struct mx3_nf_controller *mx3_nf_info = nand->controller_priv; + struct target *target = mx3_nf_info->target; + + { + /* + * validate target state + */ + int validate_target_result; + validate_target_result = validate_target_state (nand); + if (validate_target_result != ERROR_OK) + { + return validate_target_result; + } + } + + do + { + target_read_u16 (target, MX3_NF_CFG2, &poll_complete_status); + if (poll_complete_status & MX3_NF_BIT_OP_DONE) + { + return tout; + } + alive_sleep (1); + } + while (tout-- > 0); + return tout; +} + +static int imx31_write_page (struct nand_device *nand, uint32_t page, + uint8_t * data, uint32_t data_size, uint8_t * oob, + uint32_t oob_size) +{ + struct mx3_nf_controller *mx3_nf_info = nand->controller_priv; + struct target *target = mx3_nf_info->target; + + if (data_size % 2) + { + LOG_ERROR (data_block_size_err_msg, data_size); + return ERROR_NAND_OPERATION_FAILED; + } + if (oob_size % 2) + { + LOG_ERROR (data_block_size_err_msg, oob_size); + return ERROR_NAND_OPERATION_FAILED; + } + if (!data) + { + LOG_ERROR ("nothing to program"); + return ERROR_NAND_OPERATION_FAILED; + } + { + /* + * validate target state + */ + int retval; + retval = validate_target_state (nand); + if (retval != ERROR_OK) + { + return retval; + } + } + { + int retval = ERROR_OK; + retval |= imx31_command(nand, NAND_CMD_SEQIN); + retval |= imx31_address(nand, 0x00); + retval |= imx31_address(nand, page & 0xff); + retval |= imx31_address(nand, (page >> 8) & 0xff); + if (nand->address_cycles >= 4) + { + retval |= imx31_address (nand, (page >> 16) & 0xff); + if (nand->address_cycles >= 5) + { + retval |= imx31_address (nand, (page >> 24) & 0xff); + } + } + target_write_buffer (target, MX3_NF_MAIN_BUFFER0, data_size, data); + if (oob) + { + if (mx3_nf_info->flags.hw_ecc_enabled) + { + /* + * part of spare block will be overrided by hardware + * ECC generator + */ + LOG_DEBUG + ("part of spare block will be overrided by hardware ECC generator"); + } + target_write_buffer (target, MX3_NF_SPARE_BUFFER0, oob_size, + oob); + } + /* + * start data input operation (set MX3_NF_BIT_OP_DONE==0) + */ + target_write_u16 (target, MX3_NF_CFG2, MX3_NF_BIT_OP_FDI); + { + int poll_result; + poll_result = poll_for_complete_op (target, "data input"); + if (poll_result != ERROR_OK) + { + return poll_result; + } + } + retval |= imx31_command (nand, NAND_CMD_PAGEPROG); + if (retval != ERROR_OK) + { + return retval; + } + + /* + * check status register + */ + { + uint16_t nand_status_content; + retval = ERROR_OK; + retval |= imx31_command(nand, NAND_CMD_STATUS); + retval |= imx31_address(nand, 0x00); + retval |= do_data_output(nand); + if (retval != ERROR_OK) + { + LOG_ERROR (get_status_register_err_msg); + return retval; + } + target_read_u16 (target, MX3_NF_MAIN_BUFFER0, &nand_status_content); + if (nand_status_content & 0x0001) + { + /* + * is host-big-endian correctly ?? + */ + return ERROR_NAND_OPERATION_FAILED; + } + } + } + return ERROR_OK; +} + +static int imx31_read_page (struct nand_device *nand, uint32_t page, + uint8_t * data, uint32_t data_size, uint8_t * oob, + uint32_t oob_size) +{ + struct mx3_nf_controller *mx3_nf_info = nand->controller_priv; + struct target *target = mx3_nf_info->target; + + if (data_size % 2) + { + LOG_ERROR (data_block_size_err_msg, data_size); + return ERROR_NAND_OPERATION_FAILED; + } + if (oob_size % 2) + { + LOG_ERROR (data_block_size_err_msg, oob_size); + return ERROR_NAND_OPERATION_FAILED; + } + + { + /* + * validate target state + */ + int retval; + retval = validate_target_state(nand); + if (retval != ERROR_OK) + { + return retval; + } + } + { + int retval = ERROR_OK; + retval |= imx31_command(nand, NAND_CMD_READ0); + retval |= imx31_address(nand, 0x00); + retval |= imx31_address(nand, page & 0xff); + retval |= imx31_address(nand, (page >> 8) & 0xff); + if (nand->address_cycles >= 4) + { + retval |= imx31_address(nand, (page >> 16) & 0xff); + if (nand->address_cycles >= 5) + { + retval |= imx31_address(nand, (page >> 24) & 0xff); + retval |= imx31_command(nand, NAND_CMD_READSTART); + } + } + retval |= do_data_output (nand); + if (retval != ERROR_OK) + { + return retval; + } + + if (data) + { + target_read_buffer (target, MX3_NF_MAIN_BUFFER0, data_size, + data); + } + if (oob) + { + target_read_buffer (target, MX3_NF_SPARE_BUFFER0, oob_size, + oob); + } + } + return ERROR_OK; +} + +static int test_iomux_settings (struct target * target, uint32_t address, + uint32_t mask, const char *text) +{ + uint32_t register_content; + target_read_u32 (target, address, ®ister_content); + if ((register_content & mask) != (0x12121212 & mask)) + { + LOG_ERROR ("IOMUX for {%s} is bad", text); + return ERROR_FAIL; + } + return ERROR_OK; +} + +static int initialize_nf_controller (struct nand_device *nand) +{ + struct mx3_nf_controller *mx3_nf_info = nand->controller_priv; + struct target *target = mx3_nf_info->target; + /* + * resets NAND flash controller in zero time ? I dont know. + */ + target_write_u16 (target, MX3_NF_CFG1, MX3_NF_BIT_RESET_EN); + { + uint16_t work_mode; + work_mode = MX3_NF_BIT_INT_DIS; /* disable interrupt */ + if (target->endianness == TARGET_BIG_ENDIAN) + { + work_mode |= MX3_NF_BIT_BE_EN; + } + if (mx3_nf_info->flags.hw_ecc_enabled) + { + work_mode |= MX3_NF_BIT_ECC_EN; + } + target_write_u16 (target, MX3_NF_CFG1, work_mode); + } + /* + * unlock SRAM buffer for write; 2 mean "Unlock", other values means "Lock" + */ + target_write_u16 (target, MX3_NF_BUFCFG, 2); + { + uint16_t temp; + target_read_u16 (target, MX3_NF_FWP, &temp); + if ((temp & 0x0007) == 1) + { + LOG_ERROR ("NAND flash is tight-locked, reset needed"); + return ERROR_FAIL; + } + + } + /* + * unlock NAND flash for write + */ + target_write_u16 (target, MX3_NF_FWP, 4); + target_write_u16 (target, MX3_NF_LOCKSTART, 0x0000); + target_write_u16 (target, MX3_NF_LOCKEND, 0xFFFF); + /* + * 0x0000 means that first SRAM buffer @0xB800_0000 will be used + */ + target_write_u16 (target, MX3_NF_BUFADDR, 0x0000); + /* + * address of SRAM buffer + */ + in_sram_address = MX3_NF_MAIN_BUFFER0; + sign_of_sequental_byte_read = 0; + return ERROR_OK; +} + +static int get_next_byte_from_sram_buffer (struct target * target, uint8_t * value) +{ + static uint8_t even_byte = 0; + /* + * host-big_endian ?? + */ + if (sign_of_sequental_byte_read == 0) + { + even_byte = 0; + } + if (in_sram_address > MX3_NF_LAST_BUFFER_ADDR) + { + LOG_ERROR (sram_buffer_bounds_err_msg, in_sram_address); + *value = 0; + sign_of_sequental_byte_read = 0; + even_byte = 0; + return ERROR_NAND_OPERATION_FAILED; + } + else + { + uint16_t temp; + target_read_u16 (target, in_sram_address, &temp); + if (even_byte) + { + *value = temp >> 8; + even_byte = 0; + in_sram_address += 2; + } + else + { + *value = temp & 0xff; + even_byte = 1; + } + } + sign_of_sequental_byte_read = 1; + return ERROR_OK; +} + +static int get_next_halfword_from_sram_buffer (struct target * target, + uint16_t * value) +{ + if (in_sram_address > MX3_NF_LAST_BUFFER_ADDR) + { + LOG_ERROR (sram_buffer_bounds_err_msg, in_sram_address); + *value = 0; + return ERROR_NAND_OPERATION_FAILED; + } + else + { + target_read_u16 (target, in_sram_address, value); + in_sram_address += 2; + } + return ERROR_OK; +} + +static int poll_for_complete_op (struct target * target, const char *text) +{ + uint16_t poll_complete_status; + for (int poll_cycle_count = 0; poll_cycle_count < 100; poll_cycle_count++) + { + usleep (25); + target_read_u16 (target, MX3_NF_CFG2, &poll_complete_status); + if (poll_complete_status & MX3_NF_BIT_OP_DONE) + { + break; + } + } + if (!(poll_complete_status & MX3_NF_BIT_OP_DONE)) + { + LOG_ERROR ("%s sending timeout", text); + return ERROR_NAND_OPERATION_FAILED; + } + return ERROR_OK; +} + +static int validate_target_state (struct nand_device *nand) +{ + struct mx3_nf_controller *mx3_nf_info = nand->controller_priv; + struct target *target = mx3_nf_info->target; + + if (target->state != TARGET_HALTED) + { + LOG_ERROR (target_not_halted_err_msg); + return ERROR_NAND_OPERATION_FAILED; + } + + if (mx3_nf_info->flags.target_little_endian != + (target->endianness == TARGET_LITTLE_ENDIAN)) + { + /* + * endianness changed after NAND controller probed + */ + return ERROR_NAND_OPERATION_FAILED; + } + return ERROR_OK; +} + +static int do_data_output (struct nand_device *nand) +{ + struct mx3_nf_controller *mx3_nf_info = nand->controller_priv; + struct target *target = mx3_nf_info->target; + switch (mx3_nf_info->fin) + { + case MX3_NF_FIN_DATAOUT: + /* + * start data output operation (set MX3_NF_BIT_OP_DONE==0) + */ + target_write_u16 (target, MX3_NF_CFG2, + MX3_NF_BIT_DATAOUT_TYPE (mx3_nf_info-> + optype)); + { + int poll_result; + poll_result = poll_for_complete_op (target, "data output"); + if (poll_result != ERROR_OK) + { + return poll_result; + } + } + mx3_nf_info->fin = MX3_NF_FIN_NONE; + /* + * ECC stuff + */ + if ((mx3_nf_info->optype == MX3_NF_DATAOUT_PAGE) + && mx3_nf_info->flags.hw_ecc_enabled) + { + uint16_t ecc_status; + target_read_u16 (target, MX3_NF_ECCSTATUS, &ecc_status); + switch (ecc_status & 0x000c) + { + case 1 << 2: + LOG_DEBUG + ("main area readed with 1 (correctable) error"); + break; + case 2 << 2: + LOG_DEBUG + ("main area readed with more than 1 (incorrectable) error"); + return ERROR_NAND_OPERATION_FAILED; + break; + } + switch (ecc_status & 0x0003) + { + case 1: + LOG_DEBUG + ("spare area readed with 1 (correctable) error"); + break; + case 2: + LOG_DEBUG + ("main area readed with more than 1 (incorrectable) error"); + return ERROR_NAND_OPERATION_FAILED; + break; + } + } + break; + case MX3_NF_FIN_NONE: + break; + } + return ERROR_OK; +} + +struct nand_flash_controller imx31_nand_flash_controller = { + .name = "imx31", + .nand_device_command = &imx31_nand_device_command, + .init = &imx31_init, + .reset = &imx31_reset, + .command = &imx31_command, + .address = &imx31_address, + .write_data = &imx31_write_data, + .read_data = &imx31_read_data, + .write_page = &imx31_write_page, + .read_page = &imx31_read_page, + .controller_ready = &imx31_controller_ready, + .nand_ready = &imx31_nand_ready, + }; diff --git a/src/flash/nand/mx3.h b/src/flash/nand/mx3.h new file mode 100644 index 00000000..ddec92cf --- /dev/null +++ b/src/flash/nand/mx3.h @@ -0,0 +1,117 @@ + +/*************************************************************************** + * Copyright (C) 2009 by Alexei Babich * + * Rezonans plc., Chelyabinsk, Russia * + * impatt@mail.ru * + * * + * 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. * + ***************************************************************************/ + +/* + * Freescale iMX3* OpenOCD NAND Flash controller support. + * + * Many thanks to Ben Dooks for writing s3c24xx driver. + */ +#include + +#define MX3_NF_BASE_ADDR 0xb8000000 +#define MX3_NF_BUFSIZ (MX3_NF_BASE_ADDR + 0xe00) +#define MX3_NF_BUFADDR (MX3_NF_BASE_ADDR + 0xe04) +#define MX3_NF_FADDR (MX3_NF_BASE_ADDR + 0xe06) +#define MX3_NF_FCMD (MX3_NF_BASE_ADDR + 0xe08) +#define MX3_NF_BUFCFG (MX3_NF_BASE_ADDR + 0xe0a) +#define MX3_NF_ECCSTATUS (MX3_NF_BASE_ADDR + 0xe0c) +#define MX3_NF_ECCMAINPOS (MX3_NF_BASE_ADDR + 0xe0e) +#define MX3_NF_ECCSPAREPOS (MX3_NF_BASE_ADDR + 0xe10) +#define MX3_NF_FWP (MX3_NF_BASE_ADDR + 0xe12) +#define MX3_NF_LOCKSTART (MX3_NF_BASE_ADDR + 0xe14) +#define MX3_NF_LOCKEND (MX3_NF_BASE_ADDR + 0xe16) +#define MX3_NF_FWPSTATUS (MX3_NF_BASE_ADDR + 0xe18) + /* + * all bits not marked as self-clearing bit + */ +#define MX3_NF_CFG1 (MX3_NF_BASE_ADDR + 0xe1a) +#define MX3_NF_CFG2 (MX3_NF_BASE_ADDR + 0xe1c) + +#define MX3_NF_MAIN_BUFFER0 (MX3_NF_BASE_ADDR + 0x0000) +#define MX3_NF_MAIN_BUFFER1 (MX3_NF_BASE_ADDR + 0x0200) +#define MX3_NF_MAIN_BUFFER2 (MX3_NF_BASE_ADDR + 0x0400) +#define MX3_NF_MAIN_BUFFER3 (MX3_NF_BASE_ADDR + 0x0600) +#define MX3_NF_SPARE_BUFFER0 (MX3_NF_BASE_ADDR + 0x0800) +#define MX3_NF_SPARE_BUFFER1 (MX3_NF_BASE_ADDR + 0x0810) +#define MX3_NF_SPARE_BUFFER2 (MX3_NF_BASE_ADDR + 0x0820) +#define MX3_NF_SPARE_BUFFER3 (MX3_NF_BASE_ADDR + 0x0830) +#define MX3_NF_MAIN_BUFFER_LEN 512 +#define MX3_NF_SPARE_BUFFER_LEN 16 +#define MX3_NF_LAST_BUFFER_ADDR ((MX3_NF_SPARE_BUFFER3) + MX3_NF_SPARE_BUFFER_LEN - 2) + +/* bits in MX3_NF_CFG1 register */ +#define MX3_NF_BIT_SPARE_ONLY_EN (1<<2) +#define MX3_NF_BIT_ECC_EN (1<<3) +#define MX3_NF_BIT_INT_DIS (1<<4) +#define MX3_NF_BIT_BE_EN (1<<5) +#define MX3_NF_BIT_RESET_EN (1<<6) +#define MX3_NF_BIT_FORCE_CE (1<<7) + +/* bits in MX3_NF_CFG2 register */ + +/*Flash Command Input*/ +#define MX3_NF_BIT_OP_FCI (1<<0) + /* + * Flash Address Input + */ +#define MX3_NF_BIT_OP_FAI (1<<1) + /* + * Flash Data Input + */ +#define MX3_NF_BIT_OP_FDI (1<<2) + +/* see "enum mx_dataout_type" below */ +#define MX3_NF_BIT_DATAOUT_TYPE(x) ((x)<<3) +#define MX3_NF_BIT_OP_DONE (1<<15) + +#define MX3_CCM_CGR2 0x53f80028 +#define MX3_GPR 0x43fac008 +#define MX3_PCSR 0x53f8000c + +enum mx_dataout_type +{ + MX3_NF_DATAOUT_PAGE = 1, + MX3_NF_DATAOUT_NANDID = 2, + MX3_NF_DATAOUT_NANDSTATUS = 4, +}; +enum mx_nf_finalize_action +{ + MX3_NF_FIN_NONE, + MX3_NF_FIN_DATAOUT, +}; + +struct mx3_nf_flags +{ + unsigned host_little_endian:1; + unsigned target_little_endian:1; + unsigned nand_readonly:1; + unsigned one_kb_sram:1; + unsigned hw_ecc_enabled:1; +}; + +struct mx3_nf_controller +{ + struct target *target; + enum mx_dataout_type optype; + enum mx_nf_finalize_action fin; + struct mx3_nf_flags flags; +}; diff --git a/src/flash/nand/nonce.c b/src/flash/nand/nonce.c new file mode 100644 index 00000000..dae62a72 --- /dev/null +++ b/src/flash/nand/nonce.c @@ -0,0 +1,80 @@ +/*************************************************************************** + * Copyright (C) 2009 Zachary T Welch * + * * + * 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. * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "nand.h" + + +static int nonce_nand_command(struct nand_device *nand, uint8_t command) +{ + return ERROR_OK; +} +static int nonce_nand_address(struct nand_device *nand, uint8_t address) +{ + return ERROR_OK; +} +static int nonce_nand_read(struct nand_device *nand, void *data) +{ + return ERROR_OK; +} +static int nonce_nand_write(struct nand_device *nand, uint16_t data) +{ + return ERROR_OK; +} +static int nonce_nand_fast_block_write(struct nand_device *nand, + uint8_t *data, int size) +{ + return ERROR_OK; +} + +static int nonce_nand_reset(struct nand_device *nand) +{ + return nonce_nand_command(nand, NAND_CMD_RESET); +} + +static int nonce_nand_controller_ready(struct nand_device *nand, int timeout) +{ + return true; +} + +NAND_DEVICE_COMMAND_HANDLER(nonce_nand_device_command) +{ + return ERROR_OK; +} + +static int nonce_nand_init(struct nand_device *nand) +{ + return ERROR_OK; +} + +struct nand_flash_controller nonce_nand_controller = +{ + .name = "nonce", + .nand_device_command = &nonce_nand_device_command, + .init = &nonce_nand_init, + .reset = &nonce_nand_reset, + .command = &nonce_nand_command, + .address = &nonce_nand_address, + .read_data = &nonce_nand_read, + .write_data = &nonce_nand_write, + .write_block_data = &nonce_nand_fast_block_write, + .controller_ready = &nonce_nand_controller_ready, +}; diff --git a/src/flash/nand/orion.c b/src/flash/nand/orion.c new file mode 100644 index 00000000..77a03f27 --- /dev/null +++ b/src/flash/nand/orion.c @@ -0,0 +1,180 @@ +/*************************************************************************** + * Copyright (C) 2009 by Marvell Semiconductors, Inc. * + * Written by Nicolas Pitre * + * * + * 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. * + ***************************************************************************/ + +/* + * NAND controller interface for Marvell Orion/Kirkwood SoCs. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "arm_nandio.h" +#include "armv4_5.h" + + +struct orion_nand_controller +{ + struct target *target; + + struct arm_nand_data io; + + uint32_t cmd; + uint32_t addr; + uint32_t data; +}; + +#define CHECK_HALTED \ + do { \ + if (target->state != TARGET_HALTED) { \ + LOG_ERROR("NAND flash access requires halted target"); \ + return ERROR_NAND_OPERATION_FAILED; \ + } \ + } while (0) + +static int orion_nand_command(struct nand_device *nand, uint8_t command) +{ + struct orion_nand_controller *hw = nand->controller_priv; + struct target *target = hw->target; + + CHECK_HALTED; + target_write_u8(target, hw->cmd, command); + return ERROR_OK; +} + +static int orion_nand_address(struct nand_device *nand, uint8_t address) +{ + struct orion_nand_controller *hw = nand->controller_priv; + struct target *target = hw->target; + + CHECK_HALTED; + target_write_u8(target, hw->addr, address); + return ERROR_OK; +} + +static int orion_nand_read(struct nand_device *nand, void *data) +{ + struct orion_nand_controller *hw = nand->controller_priv; + struct target *target = hw->target; + + CHECK_HALTED; + target_read_u8(target, hw->data, data); + return ERROR_OK; +} + +static int orion_nand_write(struct nand_device *nand, uint16_t data) +{ + struct orion_nand_controller *hw = nand->controller_priv; + struct target *target = hw->target; + + CHECK_HALTED; + target_write_u8(target, hw->data, data); + return ERROR_OK; +} + +static int orion_nand_slow_block_write(struct nand_device *nand, uint8_t *data, int size) +{ + while (size--) + orion_nand_write(nand, *data++); + return ERROR_OK; +} + +static int orion_nand_fast_block_write(struct nand_device *nand, uint8_t *data, int size) +{ + struct orion_nand_controller *hw = nand->controller_priv; + int retval; + + hw->io.chunk_size = nand->page_size; + + retval = arm_nandwrite(&hw->io, data, size); + if (retval == ERROR_NAND_NO_BUFFER) + retval = orion_nand_slow_block_write(nand, data, size); + + return retval; +} + +static int orion_nand_reset(struct nand_device *nand) +{ + return orion_nand_command(nand, NAND_CMD_RESET); +} + +static int orion_nand_controller_ready(struct nand_device *nand, int timeout) +{ + return 1; +} + +NAND_DEVICE_COMMAND_HANDLER(orion_nand_device_command) +{ + struct orion_nand_controller *hw; + uint32_t base; + uint8_t ale, cle; + + if (CMD_ARGC != 3) { + LOG_ERROR("arguments must be: \n"); + return ERROR_NAND_DEVICE_INVALID; + } + + hw = calloc(1, sizeof(*hw)); + if (!hw) { + LOG_ERROR("no memory for nand controller\n"); + return ERROR_NAND_DEVICE_INVALID; + } + + nand->controller_priv = hw; + hw->target = get_target(CMD_ARGV[1]); + if (!hw->target) { + LOG_ERROR("target '%s' not defined", CMD_ARGV[1]); + free(hw); + return ERROR_NAND_DEVICE_INVALID; + } + + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], base); + cle = 0; + ale = 1; + + hw->data = base; + hw->cmd = base + (1 << cle); + hw->addr = base + (1 << ale); + + hw->io.target = hw->target; + hw->io.data = hw->data; + + return ERROR_OK; +} + +static int orion_nand_init(struct nand_device *nand) +{ + return ERROR_OK; +} + +struct nand_flash_controller orion_nand_controller = +{ + .name = "orion", + .command = orion_nand_command, + .address = orion_nand_address, + .read_data = orion_nand_read, + .write_data = orion_nand_write, + .write_block_data = orion_nand_fast_block_write, + .reset = orion_nand_reset, + .controller_ready = orion_nand_controller_ready, + .nand_device_command = orion_nand_device_command, + .init = orion_nand_init, +}; + diff --git a/src/flash/nand/s3c2410.c b/src/flash/nand/s3c2410.c new file mode 100644 index 00000000..3c391bce --- /dev/null +++ b/src/flash/nand/s3c2410.c @@ -0,0 +1,123 @@ +/*************************************************************************** + * Copyright (C) 2007, 2008 by Ben Dooks * + * ben@fluff.org * + * * + * 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. * + ***************************************************************************/ + +/* + * S3C2410 OpenOCD NAND Flash controller support. + * + * Many thanks to Simtec Electronics for sponsoring this work. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "s3c24xx.h" + +NAND_DEVICE_COMMAND_HANDLER(s3c2410_nand_device_command) +{ + struct s3c24xx_nand_controller *info; + CALL_S3C24XX_DEVICE_COMMAND(nand, &info); + + /* fill in the address fields for the core device */ + info->cmd = S3C2410_NFCMD; + info->addr = S3C2410_NFADDR; + info->data = S3C2410_NFDATA; + info->nfstat = S3C2410_NFSTAT; + + return ERROR_OK; +} + +static int s3c2410_init(struct nand_device *nand) +{ + struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv; + struct target *target = s3c24xx_info->target; + + target_write_u32(target, S3C2410_NFCONF, + S3C2410_NFCONF_EN | S3C2410_NFCONF_TACLS(3) | + S3C2410_NFCONF_TWRPH0(5) | S3C2410_NFCONF_TWRPH1(3)); + + return ERROR_OK; +} + +static int s3c2410_write_data(struct nand_device *nand, uint16_t data) +{ + struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv; + struct target *target = s3c24xx_info->target; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("target must be halted to use S3C24XX NAND flash controller"); + return ERROR_NAND_OPERATION_FAILED; + } + + target_write_u32(target, S3C2410_NFDATA, data); + return ERROR_OK; +} + +static int s3c2410_read_data(struct nand_device *nand, void *data) +{ + struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv; + struct target *target = s3c24xx_info->target; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("target must be halted to use S3C24XX NAND flash controller"); + return ERROR_NAND_OPERATION_FAILED; + } + + target_read_u8(target, S3C2410_NFDATA, data); + return ERROR_OK; +} + +static int s3c2410_nand_ready(struct nand_device *nand, int timeout) +{ + struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv; + struct target *target = s3c24xx_info->target; + uint8_t status; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("target must be halted to use S3C24XX NAND flash controller"); + return ERROR_NAND_OPERATION_FAILED; + } + + do { + target_read_u8(target, S3C2410_NFSTAT, &status); + + if (status & S3C2410_NFSTAT_BUSY) + return 1; + + alive_sleep(1); + } while (timeout-- > 0); + + return 0; +} + +struct nand_flash_controller s3c2410_nand_controller = { + .name = "s3c2410", + .nand_device_command = &s3c2410_nand_device_command, + .init = &s3c2410_init, + .reset = &s3c24xx_reset, + .command = &s3c24xx_command, + .address = &s3c24xx_address, + .write_data = &s3c2410_write_data, + .read_data = &s3c2410_read_data, + .write_page = s3c24xx_write_page, + .read_page = s3c24xx_read_page, + .controller_ready = &s3c24xx_controller_ready, + .nand_ready = &s3c2410_nand_ready, + }; diff --git a/src/flash/nand/s3c2412.c b/src/flash/nand/s3c2412.c new file mode 100644 index 00000000..57843053 --- /dev/null +++ b/src/flash/nand/s3c2412.c @@ -0,0 +1,79 @@ +/*************************************************************************** + * Copyright (C) 2007, 2008 by Ben Dooks * + * ben@fluff.org * + * * + * 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. * + ***************************************************************************/ + +/* + * S3C2412 OpenOCD NAND Flash controller support. + * + * Many thanks to Simtec Electronics for sponsoring this work. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "s3c24xx.h" + +NAND_DEVICE_COMMAND_HANDLER(s3c2412_nand_device_command) +{ + struct s3c24xx_nand_controller *info; + CALL_S3C24XX_DEVICE_COMMAND(nand, &info); + + /* fill in the address fields for the core device */ + info->cmd = S3C2440_NFCMD; + info->addr = S3C2440_NFADDR; + info->data = S3C2440_NFDATA; + info->nfstat = S3C2412_NFSTAT; + + return ERROR_OK; +} + +static int s3c2412_init(struct nand_device *nand) +{ + struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv; + struct target *target = s3c24xx_info->target; + + target_write_u32(target, S3C2410_NFCONF, + S3C2440_NFCONF_TACLS(3) | + S3C2440_NFCONF_TWRPH0(7) | + S3C2440_NFCONF_TWRPH1(7)); + + target_write_u32(target, S3C2440_NFCONT, + S3C2412_NFCONT_INIT_MAIN_ECC | + S3C2440_NFCONT_ENABLE); + + return ERROR_OK; +} + +struct nand_flash_controller s3c2412_nand_controller = { + .name = "s3c2412", + .nand_device_command = &s3c2412_nand_device_command, + .init = &s3c2412_init, + .reset = &s3c24xx_reset, + .command = &s3c24xx_command, + .address = &s3c24xx_address, + .write_data = &s3c24xx_write_data, + .read_data = &s3c24xx_read_data, + .write_page = s3c24xx_write_page, + .read_page = s3c24xx_read_page, + .write_block_data = &s3c2440_write_block_data, + .read_block_data = &s3c2440_read_block_data, + .controller_ready = &s3c24xx_controller_ready, + .nand_ready = &s3c2440_nand_ready, + }; diff --git a/src/flash/nand/s3c2440.c b/src/flash/nand/s3c2440.c new file mode 100644 index 00000000..d1a421e3 --- /dev/null +++ b/src/flash/nand/s3c2440.c @@ -0,0 +1,171 @@ +/*************************************************************************** + * Copyright (C) 2007, 2008 by Ben Dooks * + * ben@fluff.org * + * * + * 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. * + ***************************************************************************/ + +/* + * S3C2440 OpenOCD NAND Flash controller support. + * + * Many thanks to Simtec Electronics for sponsoring this work. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "s3c24xx.h" + + +NAND_DEVICE_COMMAND_HANDLER(s3c2440_nand_device_command) +{ + struct s3c24xx_nand_controller *info; + CALL_S3C24XX_DEVICE_COMMAND(nand, &info); + + /* fill in the address fields for the core device */ + info->cmd = S3C2440_NFCMD; + info->addr = S3C2440_NFADDR; + info->data = S3C2440_NFDATA; + info->nfstat = S3C2440_NFSTAT; + + return ERROR_OK; +} + +static int s3c2440_init(struct nand_device *nand) +{ + struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv; + struct target *target = s3c24xx_info->target; + + target_write_u32(target, S3C2410_NFCONF, + S3C2440_NFCONF_TACLS(3) | + S3C2440_NFCONF_TWRPH0(7) | + S3C2440_NFCONF_TWRPH1(7)); + + target_write_u32(target, S3C2440_NFCONT, + S3C2440_NFCONT_INITECC | S3C2440_NFCONT_ENABLE); + + return ERROR_OK; +} + +int s3c2440_nand_ready(struct nand_device *nand, int timeout) +{ + struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv; + struct target *target = s3c24xx_info->target; + uint8_t status; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("target must be halted to use S3C24XX NAND flash controller"); + return ERROR_NAND_OPERATION_FAILED; + } + + do { + target_read_u8(target, s3c24xx_info->nfstat, &status); + + if (status & S3C2440_NFSTAT_READY) + return 1; + + alive_sleep(1); + } while (timeout-- > 0); + + + return 0; +} + +/* use the fact we can read/write 4 bytes in one go via a single 32bit op */ + +int s3c2440_read_block_data(struct nand_device *nand, uint8_t *data, int data_size) +{ + struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv; + struct target *target = s3c24xx_info->target; + uint32_t nfdata = s3c24xx_info->data; + uint32_t tmp; + + LOG_INFO("%s: reading data: %p, %p, %d\n", __func__, nand, data, data_size); + + if (target->state != TARGET_HALTED) { + LOG_ERROR("target must be halted to use S3C24XX NAND flash controller"); + 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; +} + +int s3c2440_write_block_data(struct nand_device *nand, uint8_t *data, int data_size) +{ + struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv; + struct target *target = s3c24xx_info->target; + uint32_t nfdata = s3c24xx_info->data; + uint32_t tmp; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("target must be halted to use S3C24XX NAND flash controller"); + return ERROR_NAND_OPERATION_FAILED; + } + + 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; +} + +struct nand_flash_controller s3c2440_nand_controller = { + .name = "s3c2440", + .nand_device_command = &s3c2440_nand_device_command, + .init = &s3c2440_init, + .reset = &s3c24xx_reset, + .command = &s3c24xx_command, + .address = &s3c24xx_address, + .write_data = &s3c24xx_write_data, + .read_data = &s3c24xx_read_data, + .write_page = s3c24xx_write_page, + .read_page = s3c24xx_read_page, + .write_block_data = &s3c2440_write_block_data, + .read_block_data = &s3c2440_read_block_data, + .controller_ready = &s3c24xx_controller_ready, + .nand_ready = &s3c2440_nand_ready, + }; diff --git a/src/flash/nand/s3c2443.c b/src/flash/nand/s3c2443.c new file mode 100644 index 00000000..d3414771 --- /dev/null +++ b/src/flash/nand/s3c2443.c @@ -0,0 +1,80 @@ +/*************************************************************************** + * Copyright (C) 2007, 2008 by Ben Dooks * + * ben@fluff.org * + * * + * 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. * + ***************************************************************************/ + +/* + * S3C2443 OpenOCD NAND Flash controller support. + * + * Many thanks to Simtec Electronics for sponsoring this work. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "s3c24xx.h" + + +NAND_DEVICE_COMMAND_HANDLER(s3c2443_nand_device_command) +{ + struct s3c24xx_nand_controller *info; + CALL_S3C24XX_DEVICE_COMMAND(nand, &info); + + /* fill in the address fields for the core device */ + info->cmd = S3C2440_NFCMD; + info->addr = S3C2440_NFADDR; + info->data = S3C2440_NFDATA; + info->nfstat = S3C2412_NFSTAT; + + return ERROR_OK; +} + +static int s3c2443_init(struct nand_device *nand) +{ + struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv; + struct target *target = s3c24xx_info->target; + + target_write_u32(target, S3C2410_NFCONF, + S3C2440_NFCONF_TACLS(3) | + S3C2440_NFCONF_TWRPH0(7) | + S3C2440_NFCONF_TWRPH1(7)); + + target_write_u32(target, S3C2440_NFCONT, + S3C2412_NFCONT_INIT_MAIN_ECC | + S3C2440_NFCONT_ENABLE); + + return ERROR_OK; +} + +struct nand_flash_controller s3c2443_nand_controller = { + .name = "s3c2443", + .nand_device_command = &s3c2443_nand_device_command, + .init = &s3c2443_init, + .reset = &s3c24xx_reset, + .command = &s3c24xx_command, + .address = &s3c24xx_address, + .write_data = &s3c24xx_write_data, + .read_data = &s3c24xx_read_data, + .write_page = s3c24xx_write_page, + .read_page = s3c24xx_read_page, + .write_block_data = &s3c2440_write_block_data, + .read_block_data = &s3c2440_read_block_data, + .controller_ready = &s3c24xx_controller_ready, + .nand_ready = &s3c2440_nand_ready, + }; diff --git a/src/flash/nand/s3c24xx.c b/src/flash/nand/s3c24xx.c new file mode 100644 index 00000000..d305b221 --- /dev/null +++ b/src/flash/nand/s3c24xx.c @@ -0,0 +1,133 @@ +/*************************************************************************** + * Copyright (C) 2007, 2008 by Ben Dooks * + * ben@fluff.org * + * * + * 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. * + ***************************************************************************/ + +/* + * S3C24XX Series OpenOCD NAND Flash controller support. + * + * Many thanks to Simtec Electronics for sponsoring this work. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "s3c24xx.h" + + +S3C24XX_DEVICE_COMMAND() +{ + *info = NULL; + + struct s3c24xx_nand_controller *s3c24xx_info; + s3c24xx_info = malloc(sizeof(struct s3c24xx_nand_controller)); + if (s3c24xx_info == NULL) { + LOG_ERROR("no memory for nand controller\n"); + return -ENOMEM; + } + + nand->controller_priv = s3c24xx_info; + + s3c24xx_info->target = get_target(CMD_ARGV[1]); + if (s3c24xx_info->target == NULL) { + LOG_ERROR("target '%s' not defined", CMD_ARGV[1]); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + *info = s3c24xx_info; + + return ERROR_OK; +} + +int s3c24xx_reset(struct nand_device *nand) +{ + struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv; + struct target *target = s3c24xx_info->target; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("target must be halted to use S3C24XX NAND flash controller"); + return ERROR_NAND_OPERATION_FAILED; + } + + target_write_u32(target, s3c24xx_info->cmd, 0xff); + + return ERROR_OK; +} + +int s3c24xx_command(struct nand_device *nand, uint8_t command) +{ + struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv; + struct target *target = s3c24xx_info->target; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("target must be halted to use S3C24XX NAND flash controller"); + return ERROR_NAND_OPERATION_FAILED; + } + + target_write_u16(target, s3c24xx_info->cmd, command); + return ERROR_OK; +} + + +int s3c24xx_address(struct nand_device *nand, uint8_t address) +{ + struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv; + struct target *target = s3c24xx_info->target; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("target must be halted to use S3C24XX NAND flash controller"); + return ERROR_NAND_OPERATION_FAILED; + } + + target_write_u16(target, s3c24xx_info->addr, address); + return ERROR_OK; +} + +int s3c24xx_write_data(struct nand_device *nand, uint16_t data) +{ + struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv; + struct target *target = s3c24xx_info->target; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("target must be halted to use S3C24XX NAND flash controller"); + return ERROR_NAND_OPERATION_FAILED; + } + + target_write_u8(target, s3c24xx_info->data, data); + return ERROR_OK; +} + +int s3c24xx_read_data(struct nand_device *nand, void *data) +{ + struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv; + struct target *target = s3c24xx_info->target; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("target must be halted to use S3C24XX NAND flash controller"); + return ERROR_NAND_OPERATION_FAILED; + } + + target_read_u8(target, s3c24xx_info->data, data); + return ERROR_OK; +} + +int s3c24xx_controller_ready(struct nand_device *nand, int timeout) +{ + return 1; +} diff --git a/src/flash/nand/s3c24xx.h b/src/flash/nand/s3c24xx.h new file mode 100644 index 00000000..38057b27 --- /dev/null +++ b/src/flash/nand/s3c24xx.h @@ -0,0 +1,84 @@ +/*************************************************************************** + * Copyright (C) 2007, 2008 by Ben Dooks * + * ben@fluff.org * + * * + * 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. * + ***************************************************************************/ + +#ifndef S3C24xx_NAND_H +#define S3C24xx_NAND_H + +/* + * S3C24XX Series OpenOCD NAND Flash controller support. + * + * Many thanks to Simtec Electronics for sponsoring this work. + */ + +#include "nand.h" +#include "s3c24xx_regs.h" + +struct s3c24xx_nand_controller +{ + struct target *target; + + /* register addresses */ + uint32_t cmd; + uint32_t addr; + uint32_t data; + uint32_t nfstat; +}; + +/* Default to using the un-translated NAND register based address */ +#undef S3C2410_NFREG +#define S3C2410_NFREG(x) ((x) + 0x4e000000) + +#define S3C24XX_DEVICE_COMMAND() \ + COMMAND_HELPER(s3c24xx_nand_device_command, \ + struct nand_device *nand, \ + struct s3c24xx_nand_controller **info) + +S3C24XX_DEVICE_COMMAND(); + +#define CALL_S3C24XX_DEVICE_COMMAND(d, i) \ + do { \ + int retval = CALL_COMMAND_HANDLER(s3c24xx_nand_device_command, d, i); \ + if (ERROR_OK != retval) \ + return retval; \ + } while (0) + +int s3c24xx_reset(struct nand_device *nand); + +int s3c24xx_command(struct nand_device *nand, uint8_t command); +int s3c24xx_address(struct nand_device *nand, uint8_t address); + +int s3c24xx_write_data(struct nand_device *nand, uint16_t data); +int s3c24xx_read_data(struct nand_device *nand, void *data); + +int s3c24xx_controller_ready(struct nand_device *nand, int tout); + +#define s3c24xx_write_page NULL +#define s3c24xx_read_page NULL + +/* code shared between different controllers */ + +int s3c2440_nand_ready(struct nand_device *nand, int timeout); + +int s3c2440_read_block_data(struct nand_device *nand, + uint8_t *data, int data_size); +int s3c2440_write_block_data(struct nand_device *nand, + uint8_t *data, int data_size); + +#endif // S3C24xx_NAND_H diff --git a/src/flash/nand/s3c24xx_regs.h b/src/flash/nand/s3c24xx_regs.h new file mode 100644 index 00000000..c8cbe789 --- /dev/null +++ b/src/flash/nand/s3c24xx_regs.h @@ -0,0 +1,132 @@ +/*************************************************************************** + * Copyright (C) 2004, 2005 by Simtec Electronics * + * linux@simtec.co.uk * + * http://www.simtec.co.uk/products/SWLINUX/ * + * * + * 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; version 2 of the License. * + * * + * 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. * + ***************************************************************************/ + +/* + * S3C2410 NAND register definitions + */ + +#ifndef __ASM_ARM_REGS_NAND +#define __ASM_ARM_REGS_NAND "$Id: nand.h,v 1.3 2003/12/09 11:36:29 ben Exp $" + +#define S3C2410_NFREG(x) (x) + +#define S3C2410_NFCONF S3C2410_NFREG(0x00) +#define S3C2410_NFCMD S3C2410_NFREG(0x04) +#define S3C2410_NFADDR S3C2410_NFREG(0x08) +#define S3C2410_NFDATA S3C2410_NFREG(0x0C) +#define S3C2410_NFSTAT S3C2410_NFREG(0x10) +#define S3C2410_NFECC S3C2410_NFREG(0x14) + +#define S3C2440_NFCONT S3C2410_NFREG(0x04) +#define S3C2440_NFCMD S3C2410_NFREG(0x08) +#define S3C2440_NFADDR S3C2410_NFREG(0x0C) +#define S3C2440_NFDATA S3C2410_NFREG(0x10) +#define S3C2440_NFECCD0 S3C2410_NFREG(0x14) +#define S3C2440_NFECCD1 S3C2410_NFREG(0x18) +#define S3C2440_NFECCD S3C2410_NFREG(0x1C) +#define S3C2440_NFSTAT S3C2410_NFREG(0x20) +#define S3C2440_NFESTAT0 S3C2410_NFREG(0x24) +#define S3C2440_NFESTAT1 S3C2410_NFREG(0x28) +#define S3C2440_NFMECC0 S3C2410_NFREG(0x2C) +#define S3C2440_NFMECC1 S3C2410_NFREG(0x30) +#define S3C2440_NFSECC S3C2410_NFREG(0x34) +#define S3C2440_NFSBLK S3C2410_NFREG(0x38) +#define S3C2440_NFEBLK S3C2410_NFREG(0x3C) + +#define S3C2412_NFSBLK S3C2410_NFREG(0x20) +#define S3C2412_NFEBLK S3C2410_NFREG(0x24) +#define S3C2412_NFSTAT S3C2410_NFREG(0x28) +#define S3C2412_NFMECC_ERR0 S3C2410_NFREG(0x2C) +#define S3C2412_NFMECC_ERR1 S3C2410_NFREG(0x30) +#define S3C2412_NFMECC0 S3C2410_NFREG(0x34) +#define S3C2412_NFMECC1 S3C2410_NFREG(0x38) +#define S3C2412_NFSECC S3C2410_NFREG(0x3C) + +#define S3C2410_NFCONF_EN (1 << 15) +#define S3C2410_NFCONF_512BYTE (1 << 14) +#define S3C2410_NFCONF_4STEP (1 << 13) +#define S3C2410_NFCONF_INITECC (1 << 12) +#define S3C2410_NFCONF_nFCE (1 << 11) +#define S3C2410_NFCONF_TACLS(x) ((x) << 8) +#define S3C2410_NFCONF_TWRPH0(x) ((x) << 4) +#define S3C2410_NFCONF_TWRPH1(x) ((x) << 0) + +#define S3C2410_NFSTAT_BUSY (1 << 0) + +#define S3C2440_NFCONF_BUSWIDTH_8 (0 << 0) +#define S3C2440_NFCONF_BUSWIDTH_16 (1 << 0) +#define S3C2440_NFCONF_ADVFLASH (1 << 3) +#define S3C2440_NFCONF_TACLS(x) ((x) << 12) +#define S3C2440_NFCONF_TWRPH0(x) ((x) << 8) +#define S3C2440_NFCONF_TWRPH1(x) ((x) << 4) + +#define S3C2440_NFCONT_LOCKTIGHT (1 << 13) +#define S3C2440_NFCONT_SOFTLOCK (1 << 12) +#define S3C2440_NFCONT_ILLEGALACC_EN (1 << 10) +#define S3C2440_NFCONT_RNBINT_EN (1 << 9) +#define S3C2440_NFCONT_RN_FALLING (1 << 8) +#define S3C2440_NFCONT_SPARE_ECCLOCK (1 << 6) +#define S3C2440_NFCONT_MAIN_ECCLOCK (1 << 5) +#define S3C2440_NFCONT_INITECC (1 << 4) +#define S3C2440_NFCONT_nFCE (1 << 1) +#define S3C2440_NFCONT_ENABLE (1 << 0) + +#define S3C2440_NFSTAT_READY (1 << 0) +#define S3C2440_NFSTAT_nCE (1 << 1) +#define S3C2440_NFSTAT_RnB_CHANGE (1 << 2) +#define S3C2440_NFSTAT_ILLEGAL_ACCESS (1 << 3) + +#define S3C2412_NFCONF_NANDBOOT (1 << 31) +#define S3C2412_NFCONF_ECCCLKCON (1 << 30) +#define S3C2412_NFCONF_ECC_MLC (1 << 24) +#define S3C2412_NFCONF_TACLS_MASK (7 << 12) /* 1 extra bit of Tacls */ + +#define S3C2412_NFCONT_ECC4_DIRWR (1 << 18) +#define S3C2412_NFCONT_LOCKTIGHT (1 << 17) +#define S3C2412_NFCONT_SOFTLOCK (1 << 16) +#define S3C2412_NFCONT_ECC4_ENCINT (1 << 13) +#define S3C2412_NFCONT_ECC4_DECINT (1 << 12) +#define S3C2412_NFCONT_MAIN_ECC_LOCK (1 << 7) +#define S3C2412_NFCONT_INIT_MAIN_ECC (1 << 5) +#define S3C2412_NFCONT_nFCE1 (1 << 2) +#define S3C2412_NFCONT_nFCE0 (1 << 1) + +#define S3C2412_NFSTAT_ECC_ENCDONE (1 << 7) +#define S3C2412_NFSTAT_ECC_DECDONE (1 << 6) +#define S3C2412_NFSTAT_ILLEGAL_ACCESS (1 << 5) +#define S3C2412_NFSTAT_RnB_CHANGE (1 << 4) +#define S3C2412_NFSTAT_nFCE1 (1 << 3) +#define S3C2412_NFSTAT_nFCE0 (1 << 2) +#define S3C2412_NFSTAT_Res1 (1 << 1) +#define S3C2412_NFSTAT_READY (1 << 0) + +#define S3C2412_NFECCERR_SERRDATA(x) (((x) >> 21) & 0xf) +#define S3C2412_NFECCERR_SERRBIT(x) (((x) >> 18) & 0x7) +#define S3C2412_NFECCERR_MERRDATA(x) (((x) >> 7) & 0x3ff) +#define S3C2412_NFECCERR_MERRBIT(x) (((x) >> 4) & 0x7) +#define S3C2412_NFECCERR_SPARE_ERR(x) (((x) >> 2) & 0x3) +#define S3C2412_NFECCERR_MAIN_ERR(x) (((x) >> 2) & 0x3) +#define S3C2412_NFECCERR_NONE (0) +#define S3C2412_NFECCERR_1BIT (1) +#define S3C2412_NFECCERR_MULTIBIT (2) +#define S3C2412_NFECCERR_ECCAREA (3) + +#endif /* __ASM_ARM_REGS_NAND */ + diff --git a/src/flash/nonce_nand.c b/src/flash/nonce_nand.c deleted file mode 100644 index dae62a72..00000000 --- a/src/flash/nonce_nand.c +++ /dev/null @@ -1,80 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2009 Zachary T Welch * - * * - * 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. * - ***************************************************************************/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif -#include "nand.h" - - -static int nonce_nand_command(struct nand_device *nand, uint8_t command) -{ - return ERROR_OK; -} -static int nonce_nand_address(struct nand_device *nand, uint8_t address) -{ - return ERROR_OK; -} -static int nonce_nand_read(struct nand_device *nand, void *data) -{ - return ERROR_OK; -} -static int nonce_nand_write(struct nand_device *nand, uint16_t data) -{ - return ERROR_OK; -} -static int nonce_nand_fast_block_write(struct nand_device *nand, - uint8_t *data, int size) -{ - return ERROR_OK; -} - -static int nonce_nand_reset(struct nand_device *nand) -{ - return nonce_nand_command(nand, NAND_CMD_RESET); -} - -static int nonce_nand_controller_ready(struct nand_device *nand, int timeout) -{ - return true; -} - -NAND_DEVICE_COMMAND_HANDLER(nonce_nand_device_command) -{ - return ERROR_OK; -} - -static int nonce_nand_init(struct nand_device *nand) -{ - return ERROR_OK; -} - -struct nand_flash_controller nonce_nand_controller = -{ - .name = "nonce", - .nand_device_command = &nonce_nand_device_command, - .init = &nonce_nand_init, - .reset = &nonce_nand_reset, - .command = &nonce_nand_command, - .address = &nonce_nand_address, - .read_data = &nonce_nand_read, - .write_data = &nonce_nand_write, - .write_block_data = &nonce_nand_fast_block_write, - .controller_ready = &nonce_nand_controller_ready, -}; diff --git a/src/flash/orion_nand.c b/src/flash/orion_nand.c deleted file mode 100644 index 77a03f27..00000000 --- a/src/flash/orion_nand.c +++ /dev/null @@ -1,180 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2009 by Marvell Semiconductors, Inc. * - * Written by Nicolas Pitre * - * * - * 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. * - ***************************************************************************/ - -/* - * NAND controller interface for Marvell Orion/Kirkwood SoCs. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "arm_nandio.h" -#include "armv4_5.h" - - -struct orion_nand_controller -{ - struct target *target; - - struct arm_nand_data io; - - uint32_t cmd; - uint32_t addr; - uint32_t data; -}; - -#define CHECK_HALTED \ - do { \ - if (target->state != TARGET_HALTED) { \ - LOG_ERROR("NAND flash access requires halted target"); \ - return ERROR_NAND_OPERATION_FAILED; \ - } \ - } while (0) - -static int orion_nand_command(struct nand_device *nand, uint8_t command) -{ - struct orion_nand_controller *hw = nand->controller_priv; - struct target *target = hw->target; - - CHECK_HALTED; - target_write_u8(target, hw->cmd, command); - return ERROR_OK; -} - -static int orion_nand_address(struct nand_device *nand, uint8_t address) -{ - struct orion_nand_controller *hw = nand->controller_priv; - struct target *target = hw->target; - - CHECK_HALTED; - target_write_u8(target, hw->addr, address); - return ERROR_OK; -} - -static int orion_nand_read(struct nand_device *nand, void *data) -{ - struct orion_nand_controller *hw = nand->controller_priv; - struct target *target = hw->target; - - CHECK_HALTED; - target_read_u8(target, hw->data, data); - return ERROR_OK; -} - -static int orion_nand_write(struct nand_device *nand, uint16_t data) -{ - struct orion_nand_controller *hw = nand->controller_priv; - struct target *target = hw->target; - - CHECK_HALTED; - target_write_u8(target, hw->data, data); - return ERROR_OK; -} - -static int orion_nand_slow_block_write(struct nand_device *nand, uint8_t *data, int size) -{ - while (size--) - orion_nand_write(nand, *data++); - return ERROR_OK; -} - -static int orion_nand_fast_block_write(struct nand_device *nand, uint8_t *data, int size) -{ - struct orion_nand_controller *hw = nand->controller_priv; - int retval; - - hw->io.chunk_size = nand->page_size; - - retval = arm_nandwrite(&hw->io, data, size); - if (retval == ERROR_NAND_NO_BUFFER) - retval = orion_nand_slow_block_write(nand, data, size); - - return retval; -} - -static int orion_nand_reset(struct nand_device *nand) -{ - return orion_nand_command(nand, NAND_CMD_RESET); -} - -static int orion_nand_controller_ready(struct nand_device *nand, int timeout) -{ - return 1; -} - -NAND_DEVICE_COMMAND_HANDLER(orion_nand_device_command) -{ - struct orion_nand_controller *hw; - uint32_t base; - uint8_t ale, cle; - - if (CMD_ARGC != 3) { - LOG_ERROR("arguments must be: \n"); - return ERROR_NAND_DEVICE_INVALID; - } - - hw = calloc(1, sizeof(*hw)); - if (!hw) { - LOG_ERROR("no memory for nand controller\n"); - return ERROR_NAND_DEVICE_INVALID; - } - - nand->controller_priv = hw; - hw->target = get_target(CMD_ARGV[1]); - if (!hw->target) { - LOG_ERROR("target '%s' not defined", CMD_ARGV[1]); - free(hw); - return ERROR_NAND_DEVICE_INVALID; - } - - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], base); - cle = 0; - ale = 1; - - hw->data = base; - hw->cmd = base + (1 << cle); - hw->addr = base + (1 << ale); - - hw->io.target = hw->target; - hw->io.data = hw->data; - - return ERROR_OK; -} - -static int orion_nand_init(struct nand_device *nand) -{ - return ERROR_OK; -} - -struct nand_flash_controller orion_nand_controller = -{ - .name = "orion", - .command = orion_nand_command, - .address = orion_nand_address, - .read_data = orion_nand_read, - .write_data = orion_nand_write, - .write_block_data = orion_nand_fast_block_write, - .reset = orion_nand_reset, - .controller_ready = orion_nand_controller_ready, - .nand_device_command = orion_nand_device_command, - .init = orion_nand_init, -}; - diff --git a/src/flash/s3c2410_nand.c b/src/flash/s3c2410_nand.c deleted file mode 100644 index ca50c994..00000000 --- a/src/flash/s3c2410_nand.c +++ /dev/null @@ -1,123 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2007, 2008 by Ben Dooks * - * ben@fluff.org * - * * - * 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. * - ***************************************************************************/ - -/* - * S3C2410 OpenOCD NAND Flash controller support. - * - * Many thanks to Simtec Electronics for sponsoring this work. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "s3c24xx_nand.h" - -NAND_DEVICE_COMMAND_HANDLER(s3c2410_nand_device_command) -{ - struct s3c24xx_nand_controller *info; - CALL_S3C24XX_DEVICE_COMMAND(nand, &info); - - /* fill in the address fields for the core device */ - info->cmd = S3C2410_NFCMD; - info->addr = S3C2410_NFADDR; - info->data = S3C2410_NFDATA; - info->nfstat = S3C2410_NFSTAT; - - return ERROR_OK; -} - -static int s3c2410_init(struct nand_device *nand) -{ - struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv; - struct target *target = s3c24xx_info->target; - - target_write_u32(target, S3C2410_NFCONF, - S3C2410_NFCONF_EN | S3C2410_NFCONF_TACLS(3) | - S3C2410_NFCONF_TWRPH0(5) | S3C2410_NFCONF_TWRPH1(3)); - - return ERROR_OK; -} - -static int s3c2410_write_data(struct nand_device *nand, uint16_t data) -{ - struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv; - struct target *target = s3c24xx_info->target; - - if (target->state != TARGET_HALTED) { - LOG_ERROR("target must be halted to use S3C24XX NAND flash controller"); - return ERROR_NAND_OPERATION_FAILED; - } - - target_write_u32(target, S3C2410_NFDATA, data); - return ERROR_OK; -} - -static int s3c2410_read_data(struct nand_device *nand, void *data) -{ - struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv; - struct target *target = s3c24xx_info->target; - - if (target->state != TARGET_HALTED) { - LOG_ERROR("target must be halted to use S3C24XX NAND flash controller"); - return ERROR_NAND_OPERATION_FAILED; - } - - target_read_u8(target, S3C2410_NFDATA, data); - return ERROR_OK; -} - -static int s3c2410_nand_ready(struct nand_device *nand, int timeout) -{ - struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv; - struct target *target = s3c24xx_info->target; - uint8_t status; - - if (target->state != TARGET_HALTED) { - LOG_ERROR("target must be halted to use S3C24XX NAND flash controller"); - return ERROR_NAND_OPERATION_FAILED; - } - - do { - target_read_u8(target, S3C2410_NFSTAT, &status); - - if (status & S3C2410_NFSTAT_BUSY) - return 1; - - alive_sleep(1); - } while (timeout-- > 0); - - return 0; -} - -struct nand_flash_controller s3c2410_nand_controller = { - .name = "s3c2410", - .nand_device_command = &s3c2410_nand_device_command, - .init = &s3c2410_init, - .reset = &s3c24xx_reset, - .command = &s3c24xx_command, - .address = &s3c24xx_address, - .write_data = &s3c2410_write_data, - .read_data = &s3c2410_read_data, - .write_page = s3c24xx_write_page, - .read_page = s3c24xx_read_page, - .controller_ready = &s3c24xx_controller_ready, - .nand_ready = &s3c2410_nand_ready, - }; diff --git a/src/flash/s3c2412_nand.c b/src/flash/s3c2412_nand.c deleted file mode 100644 index acc6d993..00000000 --- a/src/flash/s3c2412_nand.c +++ /dev/null @@ -1,79 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2007, 2008 by Ben Dooks * - * ben@fluff.org * - * * - * 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. * - ***************************************************************************/ - -/* - * S3C2412 OpenOCD NAND Flash controller support. - * - * Many thanks to Simtec Electronics for sponsoring this work. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "s3c24xx_nand.h" - -NAND_DEVICE_COMMAND_HANDLER(s3c2412_nand_device_command) -{ - struct s3c24xx_nand_controller *info; - CALL_S3C24XX_DEVICE_COMMAND(nand, &info); - - /* fill in the address fields for the core device */ - info->cmd = S3C2440_NFCMD; - info->addr = S3C2440_NFADDR; - info->data = S3C2440_NFDATA; - info->nfstat = S3C2412_NFSTAT; - - return ERROR_OK; -} - -static int s3c2412_init(struct nand_device *nand) -{ - struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv; - struct target *target = s3c24xx_info->target; - - target_write_u32(target, S3C2410_NFCONF, - S3C2440_NFCONF_TACLS(3) | - S3C2440_NFCONF_TWRPH0(7) | - S3C2440_NFCONF_TWRPH1(7)); - - target_write_u32(target, S3C2440_NFCONT, - S3C2412_NFCONT_INIT_MAIN_ECC | - S3C2440_NFCONT_ENABLE); - - return ERROR_OK; -} - -struct nand_flash_controller s3c2412_nand_controller = { - .name = "s3c2412", - .nand_device_command = &s3c2412_nand_device_command, - .init = &s3c2412_init, - .reset = &s3c24xx_reset, - .command = &s3c24xx_command, - .address = &s3c24xx_address, - .write_data = &s3c24xx_write_data, - .read_data = &s3c24xx_read_data, - .write_page = s3c24xx_write_page, - .read_page = s3c24xx_read_page, - .write_block_data = &s3c2440_write_block_data, - .read_block_data = &s3c2440_read_block_data, - .controller_ready = &s3c24xx_controller_ready, - .nand_ready = &s3c2440_nand_ready, - }; diff --git a/src/flash/s3c2440_nand.c b/src/flash/s3c2440_nand.c deleted file mode 100644 index 556f6f1e..00000000 --- a/src/flash/s3c2440_nand.c +++ /dev/null @@ -1,171 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2007, 2008 by Ben Dooks * - * ben@fluff.org * - * * - * 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. * - ***************************************************************************/ - -/* - * S3C2440 OpenOCD NAND Flash controller support. - * - * Many thanks to Simtec Electronics for sponsoring this work. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "s3c24xx_nand.h" - - -NAND_DEVICE_COMMAND_HANDLER(s3c2440_nand_device_command) -{ - struct s3c24xx_nand_controller *info; - CALL_S3C24XX_DEVICE_COMMAND(nand, &info); - - /* fill in the address fields for the core device */ - info->cmd = S3C2440_NFCMD; - info->addr = S3C2440_NFADDR; - info->data = S3C2440_NFDATA; - info->nfstat = S3C2440_NFSTAT; - - return ERROR_OK; -} - -static int s3c2440_init(struct nand_device *nand) -{ - struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv; - struct target *target = s3c24xx_info->target; - - target_write_u32(target, S3C2410_NFCONF, - S3C2440_NFCONF_TACLS(3) | - S3C2440_NFCONF_TWRPH0(7) | - S3C2440_NFCONF_TWRPH1(7)); - - target_write_u32(target, S3C2440_NFCONT, - S3C2440_NFCONT_INITECC | S3C2440_NFCONT_ENABLE); - - return ERROR_OK; -} - -int s3c2440_nand_ready(struct nand_device *nand, int timeout) -{ - struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv; - struct target *target = s3c24xx_info->target; - uint8_t status; - - if (target->state != TARGET_HALTED) { - LOG_ERROR("target must be halted to use S3C24XX NAND flash controller"); - return ERROR_NAND_OPERATION_FAILED; - } - - do { - target_read_u8(target, s3c24xx_info->nfstat, &status); - - if (status & S3C2440_NFSTAT_READY) - return 1; - - alive_sleep(1); - } while (timeout-- > 0); - - - return 0; -} - -/* use the fact we can read/write 4 bytes in one go via a single 32bit op */ - -int s3c2440_read_block_data(struct nand_device *nand, uint8_t *data, int data_size) -{ - struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv; - struct target *target = s3c24xx_info->target; - uint32_t nfdata = s3c24xx_info->data; - uint32_t tmp; - - LOG_INFO("%s: reading data: %p, %p, %d\n", __func__, nand, data, data_size); - - if (target->state != TARGET_HALTED) { - LOG_ERROR("target must be halted to use S3C24XX NAND flash controller"); - 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; -} - -int s3c2440_write_block_data(struct nand_device *nand, uint8_t *data, int data_size) -{ - struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv; - struct target *target = s3c24xx_info->target; - uint32_t nfdata = s3c24xx_info->data; - uint32_t tmp; - - if (target->state != TARGET_HALTED) { - LOG_ERROR("target must be halted to use S3C24XX NAND flash controller"); - return ERROR_NAND_OPERATION_FAILED; - } - - 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; -} - -struct nand_flash_controller s3c2440_nand_controller = { - .name = "s3c2440", - .nand_device_command = &s3c2440_nand_device_command, - .init = &s3c2440_init, - .reset = &s3c24xx_reset, - .command = &s3c24xx_command, - .address = &s3c24xx_address, - .write_data = &s3c24xx_write_data, - .read_data = &s3c24xx_read_data, - .write_page = s3c24xx_write_page, - .read_page = s3c24xx_read_page, - .write_block_data = &s3c2440_write_block_data, - .read_block_data = &s3c2440_read_block_data, - .controller_ready = &s3c24xx_controller_ready, - .nand_ready = &s3c2440_nand_ready, - }; diff --git a/src/flash/s3c2443_nand.c b/src/flash/s3c2443_nand.c deleted file mode 100644 index 311bb697..00000000 --- a/src/flash/s3c2443_nand.c +++ /dev/null @@ -1,80 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2007, 2008 by Ben Dooks * - * ben@fluff.org * - * * - * 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. * - ***************************************************************************/ - -/* - * S3C2443 OpenOCD NAND Flash controller support. - * - * Many thanks to Simtec Electronics for sponsoring this work. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "s3c24xx_nand.h" - - -NAND_DEVICE_COMMAND_HANDLER(s3c2443_nand_device_command) -{ - struct s3c24xx_nand_controller *info; - CALL_S3C24XX_DEVICE_COMMAND(nand, &info); - - /* fill in the address fields for the core device */ - info->cmd = S3C2440_NFCMD; - info->addr = S3C2440_NFADDR; - info->data = S3C2440_NFDATA; - info->nfstat = S3C2412_NFSTAT; - - return ERROR_OK; -} - -static int s3c2443_init(struct nand_device *nand) -{ - struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv; - struct target *target = s3c24xx_info->target; - - target_write_u32(target, S3C2410_NFCONF, - S3C2440_NFCONF_TACLS(3) | - S3C2440_NFCONF_TWRPH0(7) | - S3C2440_NFCONF_TWRPH1(7)); - - target_write_u32(target, S3C2440_NFCONT, - S3C2412_NFCONT_INIT_MAIN_ECC | - S3C2440_NFCONT_ENABLE); - - return ERROR_OK; -} - -struct nand_flash_controller s3c2443_nand_controller = { - .name = "s3c2443", - .nand_device_command = &s3c2443_nand_device_command, - .init = &s3c2443_init, - .reset = &s3c24xx_reset, - .command = &s3c24xx_command, - .address = &s3c24xx_address, - .write_data = &s3c24xx_write_data, - .read_data = &s3c24xx_read_data, - .write_page = s3c24xx_write_page, - .read_page = s3c24xx_read_page, - .write_block_data = &s3c2440_write_block_data, - .read_block_data = &s3c2440_read_block_data, - .controller_ready = &s3c24xx_controller_ready, - .nand_ready = &s3c2440_nand_ready, - }; diff --git a/src/flash/s3c24xx_nand.c b/src/flash/s3c24xx_nand.c deleted file mode 100644 index 1a2ece72..00000000 --- a/src/flash/s3c24xx_nand.c +++ /dev/null @@ -1,133 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2007, 2008 by Ben Dooks * - * ben@fluff.org * - * * - * 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. * - ***************************************************************************/ - -/* - * S3C24XX Series OpenOCD NAND Flash controller support. - * - * Many thanks to Simtec Electronics for sponsoring this work. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "s3c24xx_nand.h" - - -S3C24XX_DEVICE_COMMAND() -{ - *info = NULL; - - struct s3c24xx_nand_controller *s3c24xx_info; - s3c24xx_info = malloc(sizeof(struct s3c24xx_nand_controller)); - if (s3c24xx_info == NULL) { - LOG_ERROR("no memory for nand controller\n"); - return -ENOMEM; - } - - nand->controller_priv = s3c24xx_info; - - s3c24xx_info->target = get_target(CMD_ARGV[1]); - if (s3c24xx_info->target == NULL) { - LOG_ERROR("target '%s' not defined", CMD_ARGV[1]); - return ERROR_COMMAND_SYNTAX_ERROR; - } - - *info = s3c24xx_info; - - return ERROR_OK; -} - -int s3c24xx_reset(struct nand_device *nand) -{ - struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv; - struct target *target = s3c24xx_info->target; - - if (target->state != TARGET_HALTED) { - LOG_ERROR("target must be halted to use S3C24XX NAND flash controller"); - return ERROR_NAND_OPERATION_FAILED; - } - - target_write_u32(target, s3c24xx_info->cmd, 0xff); - - return ERROR_OK; -} - -int s3c24xx_command(struct nand_device *nand, uint8_t command) -{ - struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv; - struct target *target = s3c24xx_info->target; - - if (target->state != TARGET_HALTED) { - LOG_ERROR("target must be halted to use S3C24XX NAND flash controller"); - return ERROR_NAND_OPERATION_FAILED; - } - - target_write_u16(target, s3c24xx_info->cmd, command); - return ERROR_OK; -} - - -int s3c24xx_address(struct nand_device *nand, uint8_t address) -{ - struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv; - struct target *target = s3c24xx_info->target; - - if (target->state != TARGET_HALTED) { - LOG_ERROR("target must be halted to use S3C24XX NAND flash controller"); - return ERROR_NAND_OPERATION_FAILED; - } - - target_write_u16(target, s3c24xx_info->addr, address); - return ERROR_OK; -} - -int s3c24xx_write_data(struct nand_device *nand, uint16_t data) -{ - struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv; - struct target *target = s3c24xx_info->target; - - if (target->state != TARGET_HALTED) { - LOG_ERROR("target must be halted to use S3C24XX NAND flash controller"); - return ERROR_NAND_OPERATION_FAILED; - } - - target_write_u8(target, s3c24xx_info->data, data); - return ERROR_OK; -} - -int s3c24xx_read_data(struct nand_device *nand, void *data) -{ - struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv; - struct target *target = s3c24xx_info->target; - - if (target->state != TARGET_HALTED) { - LOG_ERROR("target must be halted to use S3C24XX NAND flash controller"); - return ERROR_NAND_OPERATION_FAILED; - } - - target_read_u8(target, s3c24xx_info->data, data); - return ERROR_OK; -} - -int s3c24xx_controller_ready(struct nand_device *nand, int timeout) -{ - return 1; -} diff --git a/src/flash/s3c24xx_nand.h b/src/flash/s3c24xx_nand.h deleted file mode 100644 index fad33a0c..00000000 --- a/src/flash/s3c24xx_nand.h +++ /dev/null @@ -1,84 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2007, 2008 by Ben Dooks * - * ben@fluff.org * - * * - * 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. * - ***************************************************************************/ - -#ifndef S3C24xx_NAND_H -#define S3C24xx_NAND_H - -/* - * S3C24XX Series OpenOCD NAND Flash controller support. - * - * Many thanks to Simtec Electronics for sponsoring this work. - */ - -#include "nand.h" -#include "s3c24xx_regs_nand.h" - -struct s3c24xx_nand_controller -{ - struct target *target; - - /* register addresses */ - uint32_t cmd; - uint32_t addr; - uint32_t data; - uint32_t nfstat; -}; - -/* Default to using the un-translated NAND register based address */ -#undef S3C2410_NFREG -#define S3C2410_NFREG(x) ((x) + 0x4e000000) - -#define S3C24XX_DEVICE_COMMAND() \ - COMMAND_HELPER(s3c24xx_nand_device_command, \ - struct nand_device *nand, \ - struct s3c24xx_nand_controller **info) - -S3C24XX_DEVICE_COMMAND(); - -#define CALL_S3C24XX_DEVICE_COMMAND(d, i) \ - do { \ - int retval = CALL_COMMAND_HANDLER(s3c24xx_nand_device_command, d, i); \ - if (ERROR_OK != retval) \ - return retval; \ - } while (0) - -int s3c24xx_reset(struct nand_device *nand); - -int s3c24xx_command(struct nand_device *nand, uint8_t command); -int s3c24xx_address(struct nand_device *nand, uint8_t address); - -int s3c24xx_write_data(struct nand_device *nand, uint16_t data); -int s3c24xx_read_data(struct nand_device *nand, void *data); - -int s3c24xx_controller_ready(struct nand_device *nand, int tout); - -#define s3c24xx_write_page NULL -#define s3c24xx_read_page NULL - -/* code shared between different controllers */ - -int s3c2440_nand_ready(struct nand_device *nand, int timeout); - -int s3c2440_read_block_data(struct nand_device *nand, - uint8_t *data, int data_size); -int s3c2440_write_block_data(struct nand_device *nand, - uint8_t *data, int data_size); - -#endif // S3C24xx_NAND_H diff --git a/src/flash/s3c24xx_regs_nand.h b/src/flash/s3c24xx_regs_nand.h deleted file mode 100644 index c8cbe789..00000000 --- a/src/flash/s3c24xx_regs_nand.h +++ /dev/null @@ -1,132 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2004, 2005 by Simtec Electronics * - * linux@simtec.co.uk * - * http://www.simtec.co.uk/products/SWLINUX/ * - * * - * 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; version 2 of the License. * - * * - * 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. * - ***************************************************************************/ - -/* - * S3C2410 NAND register definitions - */ - -#ifndef __ASM_ARM_REGS_NAND -#define __ASM_ARM_REGS_NAND "$Id: nand.h,v 1.3 2003/12/09 11:36:29 ben Exp $" - -#define S3C2410_NFREG(x) (x) - -#define S3C2410_NFCONF S3C2410_NFREG(0x00) -#define S3C2410_NFCMD S3C2410_NFREG(0x04) -#define S3C2410_NFADDR S3C2410_NFREG(0x08) -#define S3C2410_NFDATA S3C2410_NFREG(0x0C) -#define S3C2410_NFSTAT S3C2410_NFREG(0x10) -#define S3C2410_NFECC S3C2410_NFREG(0x14) - -#define S3C2440_NFCONT S3C2410_NFREG(0x04) -#define S3C2440_NFCMD S3C2410_NFREG(0x08) -#define S3C2440_NFADDR S3C2410_NFREG(0x0C) -#define S3C2440_NFDATA S3C2410_NFREG(0x10) -#define S3C2440_NFECCD0 S3C2410_NFREG(0x14) -#define S3C2440_NFECCD1 S3C2410_NFREG(0x18) -#define S3C2440_NFECCD S3C2410_NFREG(0x1C) -#define S3C2440_NFSTAT S3C2410_NFREG(0x20) -#define S3C2440_NFESTAT0 S3C2410_NFREG(0x24) -#define S3C2440_NFESTAT1 S3C2410_NFREG(0x28) -#define S3C2440_NFMECC0 S3C2410_NFREG(0x2C) -#define S3C2440_NFMECC1 S3C2410_NFREG(0x30) -#define S3C2440_NFSECC S3C2410_NFREG(0x34) -#define S3C2440_NFSBLK S3C2410_NFREG(0x38) -#define S3C2440_NFEBLK S3C2410_NFREG(0x3C) - -#define S3C2412_NFSBLK S3C2410_NFREG(0x20) -#define S3C2412_NFEBLK S3C2410_NFREG(0x24) -#define S3C2412_NFSTAT S3C2410_NFREG(0x28) -#define S3C2412_NFMECC_ERR0 S3C2410_NFREG(0x2C) -#define S3C2412_NFMECC_ERR1 S3C2410_NFREG(0x30) -#define S3C2412_NFMECC0 S3C2410_NFREG(0x34) -#define S3C2412_NFMECC1 S3C2410_NFREG(0x38) -#define S3C2412_NFSECC S3C2410_NFREG(0x3C) - -#define S3C2410_NFCONF_EN (1 << 15) -#define S3C2410_NFCONF_512BYTE (1 << 14) -#define S3C2410_NFCONF_4STEP (1 << 13) -#define S3C2410_NFCONF_INITECC (1 << 12) -#define S3C2410_NFCONF_nFCE (1 << 11) -#define S3C2410_NFCONF_TACLS(x) ((x) << 8) -#define S3C2410_NFCONF_TWRPH0(x) ((x) << 4) -#define S3C2410_NFCONF_TWRPH1(x) ((x) << 0) - -#define S3C2410_NFSTAT_BUSY (1 << 0) - -#define S3C2440_NFCONF_BUSWIDTH_8 (0 << 0) -#define S3C2440_NFCONF_BUSWIDTH_16 (1 << 0) -#define S3C2440_NFCONF_ADVFLASH (1 << 3) -#define S3C2440_NFCONF_TACLS(x) ((x) << 12) -#define S3C2440_NFCONF_TWRPH0(x) ((x) << 8) -#define S3C2440_NFCONF_TWRPH1(x) ((x) << 4) - -#define S3C2440_NFCONT_LOCKTIGHT (1 << 13) -#define S3C2440_NFCONT_SOFTLOCK (1 << 12) -#define S3C2440_NFCONT_ILLEGALACC_EN (1 << 10) -#define S3C2440_NFCONT_RNBINT_EN (1 << 9) -#define S3C2440_NFCONT_RN_FALLING (1 << 8) -#define S3C2440_NFCONT_SPARE_ECCLOCK (1 << 6) -#define S3C2440_NFCONT_MAIN_ECCLOCK (1 << 5) -#define S3C2440_NFCONT_INITECC (1 << 4) -#define S3C2440_NFCONT_nFCE (1 << 1) -#define S3C2440_NFCONT_ENABLE (1 << 0) - -#define S3C2440_NFSTAT_READY (1 << 0) -#define S3C2440_NFSTAT_nCE (1 << 1) -#define S3C2440_NFSTAT_RnB_CHANGE (1 << 2) -#define S3C2440_NFSTAT_ILLEGAL_ACCESS (1 << 3) - -#define S3C2412_NFCONF_NANDBOOT (1 << 31) -#define S3C2412_NFCONF_ECCCLKCON (1 << 30) -#define S3C2412_NFCONF_ECC_MLC (1 << 24) -#define S3C2412_NFCONF_TACLS_MASK (7 << 12) /* 1 extra bit of Tacls */ - -#define S3C2412_NFCONT_ECC4_DIRWR (1 << 18) -#define S3C2412_NFCONT_LOCKTIGHT (1 << 17) -#define S3C2412_NFCONT_SOFTLOCK (1 << 16) -#define S3C2412_NFCONT_ECC4_ENCINT (1 << 13) -#define S3C2412_NFCONT_ECC4_DECINT (1 << 12) -#define S3C2412_NFCONT_MAIN_ECC_LOCK (1 << 7) -#define S3C2412_NFCONT_INIT_MAIN_ECC (1 << 5) -#define S3C2412_NFCONT_nFCE1 (1 << 2) -#define S3C2412_NFCONT_nFCE0 (1 << 1) - -#define S3C2412_NFSTAT_ECC_ENCDONE (1 << 7) -#define S3C2412_NFSTAT_ECC_DECDONE (1 << 6) -#define S3C2412_NFSTAT_ILLEGAL_ACCESS (1 << 5) -#define S3C2412_NFSTAT_RnB_CHANGE (1 << 4) -#define S3C2412_NFSTAT_nFCE1 (1 << 3) -#define S3C2412_NFSTAT_nFCE0 (1 << 2) -#define S3C2412_NFSTAT_Res1 (1 << 1) -#define S3C2412_NFSTAT_READY (1 << 0) - -#define S3C2412_NFECCERR_SERRDATA(x) (((x) >> 21) & 0xf) -#define S3C2412_NFECCERR_SERRBIT(x) (((x) >> 18) & 0x7) -#define S3C2412_NFECCERR_MERRDATA(x) (((x) >> 7) & 0x3ff) -#define S3C2412_NFECCERR_MERRBIT(x) (((x) >> 4) & 0x7) -#define S3C2412_NFECCERR_SPARE_ERR(x) (((x) >> 2) & 0x3) -#define S3C2412_NFECCERR_MAIN_ERR(x) (((x) >> 2) & 0x3) -#define S3C2412_NFECCERR_NONE (0) -#define S3C2412_NFECCERR_1BIT (1) -#define S3C2412_NFECCERR_MULTIBIT (2) -#define S3C2412_NFECCERR_ECCAREA (3) - -#endif /* __ASM_ARM_REGS_NAND */ - -- cgit v1.2.3