U-Boot
Threads by month
- ----- 2025 -----
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2002 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2001 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2000 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
November 2008
- 168 participants
- 480 discussions

06 Nov '08
Subject: [PATCH-OMAP3] OMAP3: Introduce CONFIG_OMAP3_MMC
From: Dirk Behme <dirk.behme(a)gmail.com>
Introduce CONFIG_OMAP3_MMC as proposed by Kyungmin Park.
Signed-off-by: Dirk Behme <dirk.behme(a)gmail.com>
---
drivers/mmc/Makefile | 4 +---
include/configs/omap3_beagle.h | 1 +
include/configs/omap3_evm.h | 1 +
include/configs/omap3_overo.h | 1 +
4 files changed, 4 insertions(+), 3 deletions(-)
Index: u-boot-arm/drivers/mmc/Makefile
===================================================================
--- u-boot-arm.orig/drivers/mmc/Makefile
+++ u-boot-arm/drivers/mmc/Makefile
@@ -26,9 +26,7 @@ include $(TOPDIR)/config.mk
LIB := $(obj)libmmc.a
COBJS-$(CONFIG_ATMEL_MCI) += atmel_mci.o
-COBJS-$(CONFIG_OMAP3_BEAGLE) += omap3_mmc.o
-COBJS-$(CONFIG_OMAP3_EVM) += omap3_mmc.o
-COBJS-$(CONFIG_OVERO) += omap3_mmc.o
+COBJS-$(CONFIG_OMAP3_MMC) += omap3_mmc.o
COBJS := $(COBJS-y)
SRCS := $(COBJS:.o=.c)
Index: u-boot-arm/include/configs/omap3_evm.h
===================================================================
--- u-boot-arm.orig/include/configs/omap3_evm.h
+++ u-boot-arm/include/configs/omap3_evm.h
@@ -93,6 +93,7 @@
#define CONFIG_BAUDRATE 115200
#define CONFIG_SYS_BAUDRATE_TABLE {4800, 9600, 19200, 38400, 57600, 115200}
#define CONFIG_MMC 1
+#define CONFIG_OMAP3_MMC 1
#define CONFIG_SYS_MMC_BASE 0xF0000000
#define CONFIG_DOS_PARTITION 1
Index: u-boot-arm/include/configs/omap3_overo.h
===================================================================
--- u-boot-arm.orig/include/configs/omap3_overo.h
+++ u-boot-arm/include/configs/omap3_overo.h
@@ -78,6 +78,7 @@
#define CONFIG_BAUDRATE 115200
#define CONFIG_SYS_BAUDRATE_TABLE {4800, 9600, 19200, 38400, 57600, 115200}
#define CONFIG_MMC 1
+#define CONFIG_OMAP3_MMC 1
#define CONFIG_SYS_MMC_BASE 0xF0000000
#define CONFIG_DOS_PARTITION 1
Index: u-boot-arm/include/configs/omap3_beagle.h
===================================================================
--- u-boot-arm.orig/include/configs/omap3_beagle.h
+++ u-boot-arm/include/configs/omap3_beagle.h
@@ -87,6 +87,7 @@
#define CONFIG_BAUDRATE 115200
#define CONFIG_SYS_BAUDRATE_TABLE {4800, 9600, 19200, 38400, 57600, 115200}
#define CONFIG_MMC 1
+#define CONFIG_OMAP3_MMC 1
#define CONFIG_SYS_MMC_BASE 0xF0000000
#define CONFIG_DOS_PARTITION 1
2
1
Hi All,
This patch adds support for Samsung Flex-OneNAND devices.
Flex-OneNAND combines SLC and MLC technologies into a single
device. SLC area provides increased reliability and speed, suitable
for storing code and data, such as bootloader, kernel
and root file system. MLC area provides high density and is best used
for storing user data. Users can configure the size of SLC and MLC
regions through 'onenand setboundary' command.
Signed-off-by: Rohit Hagargundgi <h.rohit(a)samsung.com>
---
diff --git a/common/cmd_onenand.c b/common/cmd_onenand.c
index 8d87b78..7260017 100644
--- a/common/cmd_onenand.c
+++ b/common/cmd_onenand.c
@@ -20,9 +20,64 @@
extern struct mtd_info onenand_mtd;
extern struct onenand_chip onenand_chip;
+loff_t flexonenand_get_addr(int block)
+{
+ struct mtd_info *mtd = &onenand_mtd;
+ struct onenand_chip *this = mtd->priv;
+ loff_t ofs;
+ int die = 0, boundary;
+
+ ofs = 0;
+ if (this->dies == 2 && block >= this->density_mask) {
+ block -= this->density_mask;
+ die = 1;
+ ofs = this->diesize[0];
+ }
+ boundary = this->boundary[die];
+ ofs += block << (this->erase_shift - 1);
+ if (block > (boundary + 1))
+ ofs += (block - boundary - 1) << (this->erase_shift - 1);
+ return ofs;
+}
+
+static int do_erase(ulong start, ulong end)
+{
+ struct mtd_info *mtd = &onenand_mtd;
+ struct onenand_chip *this = mtd->priv;
+ struct erase_info instr = {
+ .callback = NULL,
+ };
+ int i, ret;
+ ulong block;
+
+ printf("Erase block from %lu to %lu\n", start, end);
+
+ for (block = start; block <= end; block++) {
+ if (FLEXONENAND(this))
+ instr.addr = flexonenand_get_addr(block);
+ else
+ instr.addr = block << onenand_chip.erase_shift;
+
+ if (FLEXONENAND(this) && (mtd->numeraseregions > 1)) {
+ for (i = 0; i < mtd->numeraseregions &&
+ mtd->eraseregions[i].offset <= instr.addr;
i++)
+ ;
+ i--;
+ instr.len =
+ mtd->eraseregions[i].erasesize;
+ } else
+ instr.len = mtd->erasesize;
+ ret = onenand_erase(&onenand_mtd, &instr);
+ if (ret)
+ printf("erase failed %lu\n", block);
+ }
+ return 0;
+}
int do_onenand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
{
+ struct mtd_info *mtd = &onenand_mtd;
+ struct onenand_chip *this = mtd->priv;
int ret = 0;
switch (argc) {
@@ -42,11 +97,7 @@
default:
/* At least 4 args */
if (strncmp(argv[1], "erase", 5) == 0) {
- struct erase_info instr = {
- .callback = NULL,
- };
ulong start, end;
- ulong block;
char *endtail;
if (strncmp(argv[2], "block", 5) == 0) {
@@ -57,28 +108,18 @@
start = simple_strtoul(argv[2], NULL, 10);
end = simple_strtoul(argv[3], NULL, 10);
- start >>= onenand_chip.erase_shift;
- end >>= onenand_chip.erase_shift;
+ start = onenand_get_block(&onenand_mtd,
+ start, NULL);
+ end = onenand_get_block(&onenand_mtd,
+ end, NULL);
/* Don't include the end block */
- end--;
+ if (end > 0)
+ end--;
}
if (!end || end < 0)
end = start;
-
- printf("Erase block from %lu to %lu\n", start, end);
-
- for (block = start; block <= end; block++) {
- instr.addr = block <<
onenand_chip.erase_shift;
- instr.len = 1 << onenand_chip.erase_shift;
- ret = onenand_erase(&onenand_mtd, &instr);
- if (ret) {
- printf("erase failed %lu\n", block);
- break;
- }
- }
-
- return 0;
+ return do_erase(start, end);
}
if (strncmp(argv[1], "read", 4) == 0) {
@@ -134,15 +175,18 @@
ops.mode = MTD_OOB_PLACE;
- ofs = block << onenand_chip.erase_shift;
+ if (FLEXONENAND(this))
+ ofs = flexonenand_get_addr(block);
+ else
+ ofs = block << onenand_chip.erase_shift;
if (page)
ofs += page << onenand_chip.page_shift;
if (!len) {
if (oob)
- ops.ooblen = 64;
+ ops.ooblen = FLEXONENAND(this) ? 128
: 64;
else
- ops.len = 512;
+ ops.len = FLEXONENAND(this) ? 4096 :
512;
}
if (oob) {
@@ -158,6 +202,39 @@
return 0;
}
+ if (strncmp(argv[1], "setboundary", 11) == 0) {
+ unsigned die = simple_strtoul(argv[2], NULL, 0);
+ unsigned bdry = simple_strtoul(argv[3], NULL, 0);
+ int lock = 0, old;
+
+ if (!FLEXONENAND(this)) {
+ printf("Flex-OneNAND not found.\n");
+ return -1;
+ }
+
+ if (argc == 5 && strncmp(argv[4], "LOCK", 4) == 0)
+ lock = 1;
+
+ if (die >= this->dies) {
+ printf("Invalid die index\n");
+ return -1;
+ }
+
+ if (!(bdry % 2)) {
+ printf("Attempt to set even boundary
value.\n");
+ bdry += 1;
+ printf("Setting boundary to %d\n", bdry);
+ }
+
+ old = this->boundary[die] + (die *
this->density_mask);
+ ret = flexonenand_set_boundary(mtd, die, bdry,
lock);
+ if (!ret) {
+ int new = this->boundary[die] +
+ (die * this->density_mask);
+ do_erase(min(old, new) + 1, max(old, new));
+ }
+ return 0;
+ }
break;
}
@@ -172,5 +249,7 @@
"onenand write addr ofs len - write data at ofs with len from
addr\n"
"onenand erase saddr eaddr - erase block start addr to end addr\n"
"onenand block[.oob] addr block [page] [len] - "
- "read data with (block [, page]) to addr"
+ "read data with (block [, page]) to addr\n"
+ "onenand setboundary DIE BOUNDARY [LOCK] - "
+ "Change SLC boundary of Flex-OneNAND"
);
diff --git a/common/env_onenand.c b/common/env_onenand.c
--- a/common/env_onenand.c
+++ b/common/env_onenand.c
@@ -58,11 +58,14 @@
void env_relocate_spec(void)
{
+ struct onenand_chip *this = &onenand_chip;
unsigned long env_addr;
int use_default = 0;
size_t retlen;
env_addr = CONFIG_ENV_ADDR;
+ if (FLEXONENAND(this))
+ env_addr = CONFIG_ENV_ADDR_FLEX;
/* Check OneNAND exist */
if (onenand_mtd.writesize)
@@ -89,6 +92,7 @@
int saveenv(void)
{
+ struct onenand_chip *this = &onenand_chip;
unsigned long env_addr = CONFIG_ENV_ADDR;
struct erase_info instr = {
.callback = NULL,
@@ -96,6 +100,12 @@
size_t retlen;
instr.len = CONFIG_ENV_SIZE;
+ if (FLEXONENAND(this)) {
+ env_addr = CONFIG_ENV_ADDR_FLEX;
+ instr.len = CONFIG_ENV_SIZE_FLEX;
+ instr.len <<= onenand_mtd.eraseregions[0].numblocks == 1 ?
+ 1 : 0;
+ }
instr.addr = env_addr;
if (onenand_erase(&onenand_mtd, &instr)) {
printf("OneNAND: erase failed at 0x%08lx\n", env_addr);
diff --git a/drivers/mtd/onenand/onenand_base.c
b/drivers/mtd/onenand/onenand_base.c
--- a/drivers/mtd/onenand/onenand_base.c
+++ b/drivers/mtd/onenand/onenand_base.c
@@ -45,6 +45,14 @@
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 48 */
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 64 */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 80 */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 96 */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 112 */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 128 */
};
/**
@@ -83,9 +91,11 @@
if (device & ONENAND_DEVICE_IS_DDP) {
/* Device Flash Core select, NAND Flash Block Address */
int dfs = 0, density, mask;
+ int flex = device & DEVICE_IS_FLEXONENAND;
density = device >> ONENAND_DEVICE_DENSITY_SHIFT;
- mask = (1 << (density + 6));
+ density &= ONENAND_DEVICE_DENSITY_MASK;
+ mask = (1 << (density + (flex ? 4 : 6)));
if (block & mask)
dfs = 1;
@@ -109,9 +119,11 @@
if (device & ONENAND_DEVICE_IS_DDP) {
/* Device BufferRAM Select */
int dbs = 0, density, mask;
+ int flex = device & DEVICE_IS_FLEXONENAND;
density = device >> ONENAND_DEVICE_DENSITY_SHIFT;
- mask = (1 << (density + 6));
+ density &= ONENAND_DEVICE_DENSITY_MASK;
+ mask = (1 << (density + (flex ? 4 : 6)));
if (block & mask)
dbs = 1;
@@ -168,6 +180,41 @@
return ((bsa << ONENAND_BSA_SHIFT) | bsc);
}
+unsigned onenand_get_block(struct mtd_info *mtd, loff_t addr,
+ unsigned *isblkslc)
+{
+ struct onenand_chip *this = mtd->priv;
+ unsigned boundary, blk, die = 0;
+
+ if (!FLEXONENAND(this))
+ return addr >> this->erase_shift;
+
+ if (this->chipsize == 0) {
+ /* We have been called by read_boundary
+ * addr contains die index in this case
+ */
+ blk = addr * this->density_mask;
+ return blk;
+ }
+
+ if (addr >= this->diesize[0]) {
+ die = 1;
+ addr -= this->diesize[0];
+ }
+
+ boundary = this->boundary[die];
+
+ blk = addr >> (this->erase_shift - 1);
+ if (blk > boundary)
+ blk = (blk + boundary + 1) >> 1;
+
+ if (isblkslc)
+ *isblkslc = (blk <= boundary) ? 1 : 0;
+
+ blk += die ? this->density_mask : 0;
+ return blk;
+}
+
/**
* onenand_command - [DEFAULT] Send command to OneNAND device
* @param mtd MTD device structure
@@ -182,30 +229,36 @@
size_t len)
{
struct onenand_chip *this = mtd->priv;
- int value, readcmd = 0;
+ int value;
int block, page;
+ unsigned slc = 0;
+
/* Now we use page size operation */
- int sectors = 4, count = 4;
+ int sectors = 0, count = 0;
/* Address translation */
switch (cmd) {
case ONENAND_CMD_UNLOCK:
+ case ONENAND_CMD_UNLOCK_ALL:
case ONENAND_CMD_LOCK:
case ONENAND_CMD_LOCK_TIGHT:
block = -1;
page = -1;
break;
+ case FLEXONENAND_CMD_PI_ACCESS:
case ONENAND_CMD_ERASE:
case ONENAND_CMD_BUFFERRAM:
- block = (int)(addr >> this->erase_shift);
+ block = onenand_get_block(mtd, addr, NULL);
page = -1;
break;
default:
- block = (int)(addr >> this->erase_shift);
+ block = onenand_get_block(mtd, addr, &slc);
page = (int)(addr >> this->page_shift);
page &= this->page_mask;
+ if (FLEXONENAND(this) && slc)
+ page &= (this->page_mask >> 1);
break;
}
@@ -216,8 +269,11 @@
this->write_word(value,
this->base + ONENAND_REG_START_ADDRESS2);
- /* Switch to the next data buffer */
- ONENAND_SET_NEXT_BUFFERRAM(this);
+ if (ONENAND_IS_MLC(this))
+ ONENAND_SET_BUFFERRAM0(this);
+ else
+ /* Switch to the next data buffer */
+ ONENAND_SET_NEXT_BUFFERRAM(this);
return 0;
}
@@ -227,6 +283,10 @@
value = onenand_block_address(this->device_id, block);
this->write_word(value,
this->base + ONENAND_REG_START_ADDRESS1);
+ /* Select DataRAM for DDP */
+ value = onenand_bufferram_address(this->device_id, block);
+ this->write_word(value,
+ this->base + ONENAND_REG_START_ADDRESS2);
}
if (page != -1) {
@@ -235,8 +295,11 @@
switch (cmd) {
case ONENAND_CMD_READ:
case ONENAND_CMD_READOOB:
- dataram = ONENAND_SET_NEXT_BUFFERRAM(this);
- readcmd = 1;
+ if (ONENAND_IS_MLC(this))
+ dataram = ONENAND_SET_BUFFERRAM0(this);
+ else
+ /* Switch to the next data buffer */
+ dataram = ONENAND_SET_NEXT_BUFFERRAM(this);
break;
default:
@@ -253,14 +316,6 @@
value = onenand_buffer_address(dataram, sectors, count);
this->write_word(value, this->base +
ONENAND_REG_START_BUFFER);
- if (readcmd) {
- /* Select DataRAM for DDP */
- value =
- onenand_bufferram_address(this->device_id,
block);
- this->write_word(value,
- this->base +
- ONENAND_REG_START_ADDRESS2);
- }
}
/* Interrupt clear */
@@ -272,6 +327,29 @@
}
/**
+ * onenand_get_ecc - return ecc status
+ * @param mtd MTD device structure
+ */
+int onenand_get_ecc(struct mtd_info *mtd)
+{
+ struct onenand_chip *this = mtd->priv;
+ int ecc[4];
+ int i, result = 0;
+
+ for (i = 0; i < 4; i++) {
+ ecc[i] = this->read_word(this->base + ((0xFF00 + i) << 1));
+ if (!FLEXONENAND(this))
+ return ecc[i];
+ if (ecc[i] & FLEXONENAND_UNCORRECTABLE_ERROR) {
+ result = ONENAND_ECC_2BIT_ALL;
+ break;
+ }
+ }
+
+ return result;
+}
+
+/**
* onenand_wait - [DEFAULT] wait until the command is done
* @param mtd MTD device structure
* @param state state to select the max. timeout value
@@ -295,6 +373,15 @@
ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS);
+ if (interrupt & ONENAND_INT_READ) {
+ ecc = onenand_get_ecc(mtd);
+ if (ecc & ONENAND_ECC_2BIT_ALL) {
+ MTDDEBUG(MTD_DEBUG_LEVEL0,
+ "onenand_wait: ECC error = 0x%04x\n",
ecc);
+ return -EBADMSG;
+ }
+ }
+
if (ctrl & ONENAND_CTRL_ERROR) {
MTDDEBUG (MTD_DEBUG_LEVEL0,
"onenand_wait: controller error = 0x%04x\n",
ctrl);
@@ -307,15 +394,6 @@
return -EIO;
}
- if (interrupt & ONENAND_INT_READ) {
- ecc = this->read_word(this->base + ONENAND_REG_ECC_STATUS);
- if (ecc & ONENAND_ECC_2BIT_ALL) {
- MTDDEBUG (MTD_DEBUG_LEVEL0,
- "onenand_wait: ECC error = 0x%04x\n",
ecc);
- return -EBADMSG;
- }
- }
-
return 0;
}
@@ -433,10 +511,13 @@
struct onenand_chip *this = mtd->priv;
int block, page;
int i;
+ unsigned slc = 0;
- block = (int)(addr >> this->erase_shift);
+ block = onenand_get_block(mtd, addr, &slc);
page = (int)(addr >> this->page_shift);
page &= this->page_mask;
+ if (FLEXONENAND(this) && slc)
+ page &= (this->page_mask >> 1);
i = ONENAND_CURRENT_BUFFERRAM(this);
@@ -462,10 +543,13 @@
struct onenand_chip *this = mtd->priv;
int block, page;
int i;
+ unsigned slc = 0;
- block = (int)(addr >> this->erase_shift);
+ block = onenand_get_block(mtd, addr, &slc);
page = (int)(addr >> this->page_shift);
page &= this->page_mask;
+ if (FLEXONENAND(this) && slc)
+ page &= (this->page_mask >> 1);
/* Invalidate BufferRAM */
for (i = 0; i < MAX_BUFFERRAM; i++) {
@@ -573,6 +657,39 @@
}
/**
+ * onenand_recover_lsb - [Flex-OneNAND] Recover LSB page data
+ * @param mtd MTD device structure
+ * @param addr address to recover
+ * @param status return value from onenand_wait
+ *
+ * Issue recovery command when read fails on MLC area.
+ */
+static int onenand_recover_lsb(struct mtd_info *mtd, loff_t addr, int
status)
+{
+ struct onenand_chip *this = mtd->priv;
+ unsigned slc = 0;
+
+ /* check if we failed due to uncorrectable error */
+ if (status != (-EBADMSG) && status != (ONENAND_BBT_READ_ECC_ERROR))
+ return status;
+
+ /* check if address lies in MLC region */
+ onenand_get_block(mtd, addr, &slc);
+ if (slc)
+ return status;
+
+ /* We are attempting to reread, so decrement stats.failed
+ * which was incremented by onenand_wait due to read failure
+ */
+ printk(KERN_DEBUG "Attempting to recover from uncorrectable
read\n");
+ mtd->ecc_stats.failed--;
+
+ /* Issue the LSB page recovery command */
+ this->command(mtd, FLEXONENAND_CMD_RECOVER_LSB, addr,
this->writesize);
+ return this->wait(mtd, FL_READING);
+}
+
+/**
* onenand_read_ops_nolock - [OneNAND Interface] OneNAND read main and/or
out-of-band
* @param mtd MTD device structure
* @param from offset to read from
@@ -616,12 +733,15 @@
stats = mtd->ecc_stats;
/* Read-while-load method */
+ /* Note: We can't use this feature in MLC */
/* Do first load to bufferRAM */
if (read < len) {
if (!onenand_check_bufferram(mtd, from)) {
this->command(mtd, ONENAND_CMD_READ, from,
writesize);
ret = this->wait(mtd, FL_READING);
+ ret = (FLEXONENAND(this) && ret) ?
+ onenand_recover_lsb(mtd, from, ret) : ret;
onenand_update_bufferram(mtd, from, !ret);
if (ret == -EBADMSG)
ret = 0;
@@ -636,7 +756,7 @@
while (!ret) {
/* If there is more to load then start next load */
from += thislen;
- if (read + thislen < len) {
+ if (!ONENAND_IS_MLC(this) && read + thislen < len) {
this->command(mtd, ONENAND_CMD_READ, from,
writesize);
/*
* Chip boundary handling in DDP
@@ -669,6 +789,16 @@
oobcolumn = 0;
}
+ if (ONENAND_IS_MLC(this) && (read + thislen < len)) {
+ this->command(mtd, ONENAND_CMD_READ, from,
writesize);
+ ret = this->wait(mtd, FL_READING);
+ ret = (FLEXONENAND(this) && ret) ?
+ onenand_recover_lsb(mtd, from, ret) : ret;
+ onenand_update_bufferram(mtd, from, !ret);
+ if (ret == -EBADMSG)
+ ret = 0;
+ }
+
/* See if we are done */
read += thislen;
if (read == len)
@@ -676,16 +806,19 @@
/* Set up for next read from bufferRAM */
if (unlikely(boundary))
this->write_word(ONENAND_DDP_CHIP1, this->base +
ONENAND_REG_START_ADDRESS2);
- ONENAND_SET_NEXT_BUFFERRAM(this);
+ if (!ONENAND_IS_MLC(this))
+ ONENAND_SET_NEXT_BUFFERRAM(this);
buf += thislen;
thislen = min_t(int, writesize, len - read);
column = 0;
- /* Now wait for load */
- ret = this->wait(mtd, FL_READING);
- onenand_update_bufferram(mtd, from, !ret);
- if (ret == -EBADMSG)
- ret = 0;
+ if (!ONENAND_IS_MLC(this)) {
+ /* Now wait for load */
+ ret = this->wait(mtd, FL_READING);
+ onenand_update_bufferram(mtd, from, !ret);
+ if (ret == -EBADMSG)
+ ret = 0;
+ }
}
/*
@@ -722,7 +855,7 @@
size_t len = ops->ooblen;
mtd_oob_mode_t mode = ops->mode;
u_char *buf = ops->oobbuf;
- int ret = 0;
+ int ret = 0, readcmd;
from += ops->ooboffs;
@@ -755,15 +888,19 @@
stats = mtd->ecc_stats;
+ readcmd = ONENAND_IS_MLC(this) ? ONENAND_CMD_READ :
ONENAND_CMD_READOOB;
+
while (read < len) {
thislen = oobsize - column;
thislen = min_t(int, thislen, len);
- this->command(mtd, ONENAND_CMD_READOOB, from, mtd->oobsize);
+ this->command(mtd, readcmd, from, mtd->oobsize);
onenand_update_bufferram(mtd, from, 0);
ret = this->wait(mtd, FL_READING);
+ ret = (FLEXONENAND(this) && ret) ?
+ onenand_recover_lsb(mtd, from, ret) : ret;
if (ret && ret != -EBADMSG) {
printk(KERN_ERR "onenand_read_oob_nolock: read
failed = 0x%x\n", ret);
break;
@@ -886,22 +1023,26 @@
interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT);
ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS);
- /* Initial bad block case: 0x2400 or 0x0400 */
- if (ctrl & ONENAND_CTRL_ERROR) {
- printk(KERN_DEBUG "onenand_bbt_wait: controller error =
0x%04x\n", ctrl);
- return ONENAND_BBT_READ_ERROR;
- }
-
if (interrupt & ONENAND_INT_READ) {
- int ecc = this->read_word(this->base +
ONENAND_REG_ECC_STATUS);
- if (ecc & ONENAND_ECC_2BIT_ALL)
+ int ecc = onenand_get_ecc(mtd);
+ if (ecc & ONENAND_ECC_2BIT_ALL) {
+ printk(KERN_INFO "onenand_bbt_wait: ecc error =
0x%04x"
+ ", controller = 0x%04x\n", ecc, ctrl);
return ONENAND_BBT_READ_ERROR;
+ }
} else {
printk(KERN_ERR "onenand_bbt_wait: read timeout!"
"ctrl=0x%04x intr=0x%04x\n", ctrl,
interrupt);
return ONENAND_BBT_READ_FATAL_ERROR;
}
+ /* Initial bad block case: 0x2400 or 0x0400 */
+ if (ctrl & ONENAND_CTRL_ERROR) {
+ printk(KERN_DEBUG "onenand_bbt_wait: controller error"
+ " = 0x%04x\n", ctrl);
+ return ONENAND_BBT_READ_ERROR;
+ }
+
return 0;
}
@@ -918,7 +1059,7 @@
{
struct onenand_chip *this = mtd->priv;
int read = 0, thislen, column;
- int ret = 0;
+ int ret = 0, readcmd;
size_t len = ops->ooblen;
u_char *buf = ops->oobbuf;
@@ -926,6 +1067,8 @@
"onenand_bbt_read_oob: from = 0x%08x, len = %zi\n",
(unsigned int) from, len);
+ readcmd = ONENAND_IS_MLC(this) ? ONENAND_CMD_READ :
ONENAND_CMD_READOOB;
+
/* Initialize return value */
ops->oobretlen = 0;
@@ -945,7 +1088,7 @@
thislen = mtd->oobsize - column;
thislen = min_t(int, thislen, len);
- this->command(mtd, ONENAND_CMD_READOOB, from, mtd->oobsize);
+ this->command(mtd, readcmd, from, mtd->oobsize);
onenand_update_bufferram(mtd, from, 0);
@@ -987,9 +1130,11 @@
{
struct onenand_chip *this = mtd->priv;
u_char *oob_buf = this->oob_buf;
- int status, i;
+ int status, i, readcmd;
+
+ readcmd = ONENAND_IS_MLC(this) ? ONENAND_CMD_READ :
ONENAND_CMD_READOOB;
- this->command(mtd, ONENAND_CMD_READOOB, to, mtd->oobsize);
+ this->command(mtd, readcmd, to, mtd->oobsize);
onenand_update_bufferram(mtd, to, 0);
status = this->wait(mtd, FL_READING);
if (status)
@@ -1236,7 +1381,7 @@
{
struct onenand_chip *this = mtd->priv;
int column, ret = 0, oobsize;
- int written = 0;
+ int written = 0, oobcmd;
u_char *oobbuf;
size_t len = ops->ooblen;
const u_char *buf = ops->oobbuf;
@@ -1280,6 +1425,8 @@
oobbuf = this->oob_buf;
+ oobcmd = ONENAND_IS_MLC(this) ? ONENAND_CMD_PROG :
ONENAND_CMD_PROGOOB;
+
/* Loop until all data write */
while (written < len) {
int thislen = min_t(int, oobsize, len - written);
@@ -1295,7 +1442,14 @@
memcpy(oobbuf + column, buf, thislen);
this->write_bufferram(mtd, ONENAND_SPARERAM, oobbuf, 0,
mtd->oobsize);
- this->command(mtd, ONENAND_CMD_PROGOOB, to, mtd->oobsize);
+ if (ONENAND_IS_MLC(this)) {
+ /* Set main area of DataRAM to 0xff*/
+ memset(this->page_buf, 0xff, mtd->writesize);
+ this->write_bufferram(mtd, ONENAND_DATARAM,
+ this->page_buf, 0, mtd->writesize);
+ }
+
+ this->command(mtd, oobcmd, to, mtd->oobsize);
onenand_update_bufferram(mtd, to, 0);
if (ONENAND_IS_2PLANE(this)) {
@@ -1424,19 +1578,30 @@
unsigned int block_size;
loff_t addr;
int len;
- int ret = 0;
+ int ret = 0, i = 0;
MTDDEBUG (MTD_DEBUG_LEVEL3,
"onenand_erase: start = 0x%08x, len = %i\n",
(unsigned int)instr->addr, (unsigned int)ins tr->len);
- block_size = (1 << this->erase_shift);
+ if (FLEXONENAND(this) && (mtd->numeraseregions > 1)) {
+ for (; i < mtd->numeraseregions &&
+ instr->addr >= mtd->eraseregions[i].offset; i++)
+ ;
+ i--;
+ block_size = mtd->eraseregions[i].erasesize;
+ } else
+ block_size = mtd->erasesize;
/* Start address must align on block boundary */
if (unlikely(instr->addr & (block_size - 1))) {
- MTDDEBUG (MTD_DEBUG_LEVEL0,
- "onenand_erase: Unaligned address\n");
- return -EINVAL;
+ /* We come here if boundary is even value. Just skip for
now.*/
+ if (!FLEXONENAND(this) ||
+ (instr->addr & ((block_size >> 1) - 1))) {
+ MTDDEBUG(MTD_DEBUG_LEVEL0, "onenand_erase:"
+ " Unaligned address\n");
+ return -EINVAL;
+ }
}
/* Length must align on block boundary */
@@ -1466,7 +1631,13 @@
while (len) {
- /* TODO Check badblock */
+ /* Check if we have a bad block, we do not erase bad blocks
*/
+ if (onenand_block_isbad_nolock(mtd, addr, 0)) {
+ printk(KERN_WARNING "onenand_erase: attempt to
erase"
+ "bad block at addr 0x%08x\n", (unsigned int)
addr);
+ instr->state = MTD_ERASE_FAILED;
+ goto erase_exit;
+ }
this->command(mtd, ONENAND_CMD_ERASE, addr, block_size);
@@ -1481,7 +1652,7 @@
else
MTDDEBUG (MTD_DEBUG_LEVEL0, "onenand_erase:
"
"Failed erase, block %d\n",
- (unsigned)(addr >>
this->erase_shift));
+ onenand_get_block(mtd, addr, NULL));
instr->state = MTD_ERASE_FAILED;
instr->fail_addr = addr;
goto erase_exit;
@@ -1489,6 +1660,12 @@
len -= block_size;
addr += block_size;
+ if (FLEXONENAND(this) && (mtd->numeraseregions > 1)) {
+ if ((i < (mtd->numeraseregions - 1)) &&
+ (addr == mtd->eraseregions[i + 1].offset))
+ i++;
+ block_size = mtd->eraseregions[i].erasesize;
+ }
}
instr->state = MTD_ERASE_DONE;
@@ -1539,7 +1716,7 @@
return -EINVAL;
onenand_get_device(mtd, FL_READING);
- ret = onenand_block_isbad_nolock(mtd,ofs, 0);
+ ret = onenand_block_isbad_nolock(mtd, ofs, 0);
onenand_release_device(mtd);
return ret;
}
@@ -1581,8 +1758,8 @@
struct onenand_chip *this = mtd->priv;
int start, end, block, value, status;
- start = ofs >> this->erase_shift;
- end = len >> this->erase_shift;
+ start = onenand_get_block(mtd, ofs, NULL);
+ end = onenand_get_block(mtd, ofs + len, NULL) - 1;
/* Continuous lock scheme */
if (this->options & ONENAND_CONT_LOCK) {
@@ -1590,7 +1767,7 @@
this->write_word(start,
this->base +
ONENAND_REG_START_BLOCK_ADDRESS);
/* Set end block address */
- this->write_word(end - 1,
+ this->write_word(end,
this->base +
ONENAND_REG_END_BLOCK_ADDRESS);
/* Write unlock command */
this->command(mtd, ONENAND_CMD_UNLOCK, 0, 0);
@@ -1612,12 +1789,23 @@
}
/* Block lock scheme */
- for (block = start; block < end; block++) {
+ for (block = start; block < end + 1; block++) {
+ /* Set block address */
+ value = onenand_block_address(this->device_id, block);
+ this->write_word(value,
+ this->base + ONENAND_REG_START_ADDRESS1);
+ /* Select DataRAM for DDP */
+ value = onenand_bufferram_address(this->device_id, block);
+ this->write_word(value,
+ this->base + ONENAND_REG_START_ADDRESS2);
/* Set start block address */
this->write_word(block,
this->base +
ONENAND_REG_START_BLOCK_ADDRESS);
/* Write unlock command */
- this->command(mtd, ONENAND_CMD_UNLOCK, 0, 0);
+ if (FLEXONENAND(this))
+ this->command(mtd, ONENAND_CMD_UNLOCK_ALL, 0, 0);
+ else
+ this->command(mtd, ONENAND_CMD_UNLOCK, 0, 0);
/* There's no return value */
this->wait(mtd, FL_UNLOCKING);
@@ -1643,6 +1831,25 @@
}
/**
+ * flexonenand_unlock_all - [FlexOneNAND Interface] unlock all blocks
+ * @param mtd MTD device structure
+ *
+ * Unlock all blocks
+ */
+static int flexonenand_unlock_all(struct mtd_info *mtd)
+{
+ struct onenand_chip *this = mtd->priv;
+ size_t len = mtd->erasesize;
+
+ if (mtd->numeraseregions > 1)
+ len >>= 1;
+ onenand_unlock(mtd, 0, len);
+ if (this->device_id & ONENAND_DEVICE_IS_DDP)
+ onenand_unlock(mtd, this->diesize[0], len);
+ return 0;
+}
+
+/**
* onenand_print_device_info - Print device ID
* @param device device ID
*
@@ -1650,15 +1857,18 @@
*/
char * onenand_print_device_info(int device)
{
- int vcc, demuxed, ddp, density;
+ int vcc, demuxed, ddp, density, flexonenand;
char *dev_info = malloc(80);
vcc = device & ONENAND_DEVICE_VCC_MASK;
demuxed = device & ONENAND_DEVICE_IS_DEMUX;
ddp = device & ONENAND_DEVICE_IS_DDP;
density = device >> ONENAND_DEVICE_DENSITY_SHIFT;
- sprintf(dev_info, "%sOneNAND%s %dMB %sV 16-bit (0x%02x)",
- demuxed ? "" : "Muxed ",
+ density &= ONENAND_DEVICE_DENSITY_MASK;
+ flexonenand = device & DEVICE_IS_FLEXONENAND;
+ sprintf(dev_info, "%s%sOneNAND%s %dMB %sV 16-bit (0x%02x)",
+ flexonenand ? "Flex-" : "",
+ demuxed ? "" : "Mux",
ddp ? "(DDP)" : "",
(16 << density), vcc ? "2.65/3.3" : "1.8", device);
@@ -1694,6 +1904,174 @@
}
/**
+* flexonenand_get_boundary - Reads the SLC boundary
+* @param onenand_info onenand info structure
+**/
+static int flexonenand_get_boundary(struct mtd_info *mtd)
+{
+ struct onenand_chip *this = mtd->priv;
+ unsigned die, bdry;
+ int ret, syscfg, unlocked;
+
+ /* Disable ECC */
+ syscfg = this->read_word(this->base + ONENAND_REG_SYS_CFG1);
+ this->write_word((syscfg | 0x0100), this->base +
ONENAND_REG_SYS_CFG1);
+
+ for (die = 0; die < this->dies; die++) {
+ this->command(mtd, FLEXONENAND_CMD_PI_ACCESS, die, 0);
+ this->wait(mtd, FL_SYNCING);
+
+ this->command(mtd, ONENAND_CMD_READ, die, 0);
+ ret = this->wait(mtd, FL_READING);
+
+ bdry = this->read_word(this->base + ONENAND_DATARAM);
+ unlocked = bdry >> FLEXONENAND_PI_UNLOCK_SHIFT;
+ unlocked = (unlocked == 0x3) ? 1 : 0;
+ this->boundary[die] = bdry & FLEXONENAND_PI_MASK;
+
+ this->command(mtd, ONENAND_CMD_RESET, 0, 0);
+ ret = this->wait(mtd, FL_RESETING);
+
+ printk(KERN_INFO "Die %d boundary: %d%s\n", die,
+ this->boundary[die],
+ unlocked ? "(Unlocked)" : "(Locked)");
+ }
+
+ /* Enable ECC */
+ this->write_word(syscfg, this->base + ONENAND_REG_SYS_CFG1);
+ return 0;
+}
+
+/**
+ * get_flexonenand_size - Fill up fields in onenand_chip
+ * boundary[], diesize[], chipsize
+ * @param mtd - MTD device structure
+ */
+void get_flexonenand_size(struct mtd_info *mtd)
+{
+ struct onenand_chip *this = mtd->priv;
+ int die, ofs, i, eraseshift;
+ unsigned blksperdie = 1024;
+ unsigned maxbdry = blksperdie - 1;
+
+ eraseshift = this->erase_shift - 1;
+
+ this->chipsize = 0;
+ mtd->numeraseregions = this->dies << 1;
+
+ /* This fills up the device boundary */
+ flexonenand_get_boundary(mtd);
+ die = ofs = 0;
+ i = -1;
+ for (; die < this->dies; die++) {
+ if (!die || this->boundary[die-1] != maxbdry) {
+ i++;
+ mtd->eraseregions[i].offset = ofs;
+ mtd->eraseregions[i].erasesize = 1 << eraseshift;
+ mtd->eraseregions[i].numblocks = this->boundary[die]
+ 1;
+ ofs += mtd->eraseregions[i].numblocks << eraseshift;
+ eraseshift++;
+ } else {
+ mtd->numeraseregions -= 1;
+ mtd->eraseregions[i].numblocks +=
this->boundary[die] + 1;
+ ofs += (this->boundary[die] + 1) << (eraseshift -
1);
+ }
+ if (this->boundary[die] != maxbdry) {
+ i++;
+ mtd->eraseregions[i].offset = ofs;
+ mtd->eraseregions[i].erasesize = 1 << eraseshift;
+ mtd->eraseregions[i].numblocks =
+ maxbdry ^ this->boundary[die];
+ ofs += mtd->eraseregions[i].numblocks << eraseshift;
+ eraseshift--;
+ } else
+ mtd->numeraseregions -= 1;
+ }
+
+ mtd->erasesize = 1 << (this->erase_shift);
+ if (mtd->numeraseregions == 1)
+ mtd->erasesize >>= 1;
+
+ printk(KERN_INFO "Device has %d eraseregions\n",
mtd->numeraseregions);
+ for (i = 0; i < mtd->numeraseregions; i++)
+ printk(KERN_INFO "[offset: 0x%08x, erasesize: 0x%05x,"
+ " numblocks: %04u]\n", mtd->eraseregions[i].offset,
+ mtd->eraseregions[i].erasesize,
+ mtd->eraseregions[i].numblocks);
+
+ eraseshift = this->erase_shift;
+ for (die = 0, mtd->size = 0; die < this->dies; die++) {
+ this->diesize[die] = (blksperdie << eraseshift);
+ this->diesize[die] -= (this->boundary[die] + 1)
+ << (eraseshift - 1);
+ mtd->size += this->diesize[die];
+ }
+ /* this->chipsize represents maximum possible chip size */
+ this->chipsize = (blksperdie << eraseshift) << (this->dies - 1);
+}
+
+/**
+* flexonenand_set_boundary - Writes the SLC boundary
+* @param onenand_info onenand info structure
+**/
+int flexonenand_set_boundary(struct mtd_info *mtd, unsigned die,
+ int boundary, int lock)
+{
+ struct onenand_chip *this = mtd->priv;
+ int ret, density, blksperdie;
+ unsigned addr;
+
+ density = this->device_id >> ONENAND_DEVICE_DENSITY_SHIFT;
+ density &= ONENAND_DEVICE_DENSITY_MASK;
+
+ blksperdie = ((16 << density) << 20) >> this->erase_shift;
+ blksperdie >>= (this->device_id & ONENAND_DEVICE_IS_DDP) ? 1 : 0;
+
+ addr = die ? this->diesize[0] : 0;
+
+ if (this->boundary[die] == boundary)
+ return -1;
+
+ printk(KERN_INFO "Changing boundary: %d%s\n", boundary, lock ?
+ "(Locked)" : "(Unlocked)");
+ if (boundary >= blksperdie) {
+ printk(KERN_ERR "Invalid boundary value.\n");
+ return -1;
+ }
+
+ boundary &= FLEXONENAND_PI_MASK;
+ boundary |= lock ? 0 : (3 << FLEXONENAND_PI_UNLOCK_SHIFT);
+
+ this->command(mtd, FLEXONENAND_CMD_PI_ACCESS, addr, 0);
+ this->wait(mtd, FL_SYNCING);
+
+ this->command(mtd, ONENAND_CMD_ERASE, addr, 0);
+ this->wait(mtd, FL_ERASING);
+
+ this->write_word(boundary, this->base + ONENAND_DATARAM);
+ this->command(mtd, ONENAND_CMD_PROG, addr, 0);
+ ret = this->wait(mtd, FL_WRITING);
+ if (ret) {
+ printk(KERN_ERR "Failed PI write for Die %d\n", die);
+ goto out;
+ }
+
+ this->command(mtd, FLEXONENAND_CMD_PI_UPDATE, addr, 0);
+ ret = this->wait(mtd, FL_WRITING);
+ if (ret)
+ printk(KERN_ERR "Failed PI update for Die %d\n", die);
+ else
+ printk(KERN_INFO "Done\n");
+out:
+ this->write_word(ONENAND_CMD_RESET, this->base +
ONENAND_REG_COMMAND);
+ this->wait(mtd, FL_RESETING);
+ if (!ret)
+ /* Recalculate device size on boundary change*/
+ get_flexonenand_size(mtd);
+ return ret;
+}
+
+/**
* onenand_probe - [OneNAND Interface] Probe the OneNAND device
* @param mtd MTD device structure
*
@@ -1727,31 +2105,47 @@
/* Read manufacturer and device IDs from Register */
maf_id = this->read_word(this->base + ONENAND_REG_MANUFACTURER_ID);
dev_id = this->read_word(this->base + ONENAND_REG_DEVICE_ID);
+ this->technology = this->read_word(this->base +
ONENAND_REG_TECHNOLOGY);
/* Check OneNAND device */
if (maf_id != bram_maf_id || dev_id != bram_dev_id)
return -ENXIO;
- /* FIXME : Current OneNAND MTD doesn't support Flex-OneNAND */
- if (dev_id & (1 << 9)) {
- printk("Not yet support Flex-OneNAND\n");
- return -ENXIO;
- }
-
/* Flash device information */
mtd->name = onenand_print_device_info(dev_id);
this->device_id = dev_id;
density = dev_id >> ONENAND_DEVICE_DENSITY_SHIFT;
- this->chipsize = (16 << density) << 20;
+ density &= ONENAND_DEVICE_DENSITY_MASK;
+ if (FLEXONENAND(this)) {
+ this->dies = (dev_id & ONENAND_DEVICE_IS_DDP) ? 2 : 1;
+ /* Maximum possible erase regions */
+ mtd->numeraseregions = this->dies << 1;
+ mtd->eraseregions = malloc(sizeof(struct
mtd_erase_region_info)
+ * (this->dies << 1));
+ if (!mtd->eraseregions)
+ return -ENOMEM;
+ }
+ this->chipsize = FLEXONENAND(this) ? 0 : (16 << density) << 20;
+ /* Set density mask. it is used for DDP */
+ if (dev_id & ONENAND_DEVICE_IS_DDP)
+ this->density_mask = (1 << (density + (FLEXONENAND(this) ?
+ 4 : 6)));
+ else
+ this->density_mask = 0;
/* OneNAND page size & block size */
/* The data buffer size is equal to page size */
mtd->writesize =
this->read_word(this->base + ONENAND_REG_DATA_BUFFER_SIZE);
+ /* We use the full BufferRAM */
+ if (ONENAND_IS_MLC(this))
+ mtd->writesize <<= 1;
+
mtd->oobsize = mtd->writesize >> 5;
/* Pagers per block is always 64 in OneNAND */
mtd->erasesize = mtd->writesize << 6;
+ mtd->erasesize <<= FLEXONENAND(this) ? 1 : 0;
this->erase_shift = ffs(mtd->erasesize) - 1;
this->page_shift = ffs(mtd->writesize) - 1;
@@ -1762,7 +2156,10 @@
/* REVIST: Multichip handling */
- mtd->size = this->chipsize;
+ if (FLEXONENAND(this))
+ get_flexonenand_size(mtd);
+ else
+ mtd->size = this->chipsize;
/* Version ID */
version_id = this->read_word(this->base + ONENAND_REG_VERSION_ID);
@@ -1787,6 +2184,11 @@
mtd->block_isbad = onenand_block_isbad;
mtd->block_markbad = onenand_block_markbad;
+ if (FLEXONENAND(this)) {
+ this->options &= ~ONENAND_CONT_LOCK;
+ this->options |= ONENAND_UNLOCK_ALL;
+ }
+
return 0;
}
@@ -1850,7 +2252,8 @@
this->options |= ONENAND_OOBBUF_ALLOC;
}
- onenand_unlock(mtd, 0, mtd->size);
+ FLEXONENAND(this) ? flexonenand_unlock_all(mtd) :
+ onenand_unlock(mtd, 0, mtd->size);
return onenand_default_bbt(mtd);
}
diff --git a/drivers/mtd/onenand/onenand_bbt.c
b/drivers/mtd/onenand/onenand_bbt.c
--- a/drivers/mtd/onenand/onenand_bbt.c
+++ b/drivers/mtd/onenand/onenand_bbt.c
@@ -66,6 +66,7 @@
struct bbm_info *bbm = this->bbm;
int i, j, numblocks, len, scanlen;
int startblock;
+ unsigned slc;
loff_t from;
size_t readlen, ooblen;
struct mtd_oob_ops ops;
@@ -82,7 +83,7 @@
/* Note that numblocks is 2 * (real numblocks) here;
* see i += 2 below as it makses shifting and masking less painful
*/
- numblocks = mtd->size >> (bbm->bbt_erase_shift - 1);
+ numblocks = this->chipsize >> (bbm->bbt_erase_shift - 1);
startblock = 0;
from = 0;
@@ -115,7 +116,13 @@
}
}
i += 2;
- from += (1 << bbm->bbt_erase_shift);
+ if (FLEXONENAND(this)) {
+ onenand_get_block(mtd, from, &slc);
+ from += (1 << bbm->bbt_erase_shift) >> 1;
+ if (!slc)
+ from += (1 << bbm->bbt_erase_shift) >> 1;
+ } else
+ from += (1 << bbm->bbt_erase_shift);
}
return 0;
@@ -152,7 +159,7 @@
uint8_t res;
/* Get block number * 2 */
- block = (int)(offs >> (bbm->bbt_erase_shift - 1));
+ block = (int) (onenand_get_block(mtd, offs, NULL) << 1);
res = (bbm->bbt[block >> 3] >> (block & 0x06)) & 0x03;
MTDDEBUG (MTD_DEBUG_LEVEL2,
@@ -191,7 +198,7 @@
struct bbm_info *bbm = this->bbm;
int len, ret = 0;
- len = mtd->size >> (this->erase_shift + 2);
+ len = this->chipsize >> (this->erase_shift + 2);
/* Allocate memory (2bit per block) */
bbm->bbt = malloc(len);
if (!bbm->bbt) {
diff --git a/drivers/mtd/onenand/onenand_uboot.c
b/drivers/mtd/onenand/onenand_uboot.c
--- a/drivers/mtd/onenand/onenand_uboot.c
+++ b/drivers/mtd/onenand/onenand_uboot.c
@@ -31,6 +31,8 @@
onenand_scan(&onenand_mtd, 1);
+ if (onenand_chip.device_id & DEVICE_IS_FLEXONENAND)
+ puts("Flex-");
puts("OneNAND: ");
- print_size(onenand_mtd.size, "\n");
+ print_size(onenand_chip.chipsize, "\n");
}
diff --git a/include/configs/apollon.h b/include/configs/apollon.h
--- a/include/configs/apollon.h
+++ b/include/configs/apollon.h
@@ -73,6 +73,7 @@
* Size of malloc() pool
*/
#define CONFIG_ENV_SIZE SZ_128K /* Total Size of Environment Sector
*/
+#define CONFIG_ENV_SIZE_FLEX SZ_256K /* Can change to 512K */
#define CFG_MALLOC_LEN (CONFIG_ENV_SIZE + SZ_128K)
#define CFG_GBL_DATA_SIZE 128 /* bytes reserved for
initial data */
@@ -227,5 +228,5 @@
#define CFG_ONENAND_BASE 0x00000000
#define CONFIG_ENV_IS_IN_ONENAND 1
#define CONFIG_ENV_ADDR 0x00020000
-
+#define CONFIG_ENV_ADDR_FLEX 0x00040000
#endif /* __CONFIG_H */
diff --git a/include/linux/mtd/onenand.h b/include/linux/mtd/onenand.h
--- a/include/linux/mtd/onenand.h
+++ b/include/linux/mtd/onenand.h
@@ -20,6 +20,7 @@
#include <linux/mtd/compat.h>
#include <linux/mtd/bbm.h>
+#define MAX_DIES 2
#define MAX_BUFFERRAM 2
#define MAX_ONENAND_PAGESIZE (2048 + 64)
@@ -43,6 +44,9 @@
/**
* struct onenand_chip - OneNAND Private Flash Chip Data
* @param base [BOARDSPECIFIC] address to access OneNAND
+ * @dies: [INTERN][FLEXONENAND] number of dies on chip
+ * @boundary: [INTERN][FLEXONENAND] Boundary of the dies
+ * @diesize: [INTERN][FLEXONENAND] Size of the dies
* @param chipsize [INTERN] the size of one chip for multichip arrays
* @param device_id [INTERN] device ID
* @param verstion_id [INTERN] version ID
@@ -67,8 +71,13 @@
*/
struct onenand_chip {
void __iomem *base;
+ unsigned int dies;
+ unsigned int boundary[MAX_DIES];
+ unsigned int diesize[MAX_DIES];
unsigned int chipsize;
unsigned int device_id;
+ unsigned int technology;
+ unsigned int density_mask;
unsigned int options;
unsigned int erase_shift;
@@ -116,6 +125,8 @@
#define ONENAND_SET_BUFFERRAM0(this) (this->bufferram_index = 0)
#define ONENAND_SET_BUFFERRAM1(this) (this->bufferram_index = 1)
+#define FLEXONENAND(this) (this->device_id & DEVICE_IS_FLEXONENAND)
+#define ONENAND_IS_MLC(this) (this->technology &
ONENAND_TECHNOLOGY_IS_MLC)
#define ONENAND_IS_DDP(this) \
(this->device_id & ONENAND_DEVICE_IS_DDP)
@@ -127,6 +138,7 @@
#define ONENAND_CONT_LOCK (0x0001)
#define ONENAND_PAGEBUF_ALLOC (0x1000)
#define ONENAND_OOBBUF_ALLOC (0x2000)
+#define ONENAND_UNLOCK_ALL (0x0002)
/*
* OneNAND Flash Manufacturer ID Codes
@@ -147,4 +159,8 @@
int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from,
struct mtd_oob_ops *ops);
+unsigned onenand_get_block(struct mtd_info *mtd, loff_t addr,
+ unsigned *isblkslc);
+int flexonenand_set_boundary(struct mtd_info *mtd, unsigned die,
+ int bdry, int lock);
#endif /* __LINUX_MTD_ONENAND_H */
diff --git a/include/linux/mtd/onenand_regs.h
b/include/linux/mtd/onenand_regs.h
--- a/include/linux/mtd/onenand_regs.h
+++ b/include/linux/mtd/onenand_regs.h
@@ -67,6 +67,10 @@
/*
* Device ID Register F001h (R)
*/
+#define DEVICE_IS_FLEXONENAND (1 << 9)
+#define FLEXONENAND_PI_MASK (0x3ff)
+#define FLEXONENAND_PI_UNLOCK_SHIFT (14)
+#define ONENAND_DEVICE_DENSITY_MASK (0xf)
#define ONENAND_DEVICE_DENSITY_SHIFT (4)
#define ONENAND_DEVICE_IS_DDP (1 << 3)
#define ONENAND_DEVICE_IS_DEMUX (1 << 2)
@@ -80,6 +84,11 @@
#define ONENAND_VERSION_PROCESS_SHIFT (8)
/*
+ * Technology Register F006h (R)
+ */
+#define ONENAND_TECHNOLOGY_IS_MLC (1 << 0)
+
+/*
* Start Address 1 F100h (R/W)
*/
#define ONENAND_DDP_SHIFT (15)
@@ -89,7 +98,7 @@
/*
* Start Address 8 F107h (R/W)
*/
-#define ONENAND_FPA_MASK (0x3f)
+#define ONENAND_FPA_MASK (0x7f)
#define ONENAND_FPA_SHIFT (2)
#define ONENAND_FSA_MASK (0x03)
@@ -101,7 +110,7 @@
#define ONENAND_BSA_BOOTRAM (0 << 2)
#define ONENAND_BSA_DATARAM0 (2 << 2)
#define ONENAND_BSA_DATARAM1 (3 << 2)
-#define ONENAND_BSC_MASK (0x03)
+#define ONENAND_BSC_MASK (0x07)
/*
* Command Register F220h (R/W)
@@ -113,9 +122,14 @@
#define ONENAND_CMD_UNLOCK (0x23)
#define ONENAND_CMD_LOCK (0x2A)
#define ONENAND_CMD_LOCK_TIGHT (0x2C)
+#define ONENAND_CMD_UNLOCK_ALL (0x27)
#define ONENAND_CMD_ERASE (0x94)
#define ONENAND_CMD_RESET (0xF0)
#define ONENAND_CMD_READID (0x90)
+#define FLEXONENAND_CMD_RESET (0xF3)
+#define FLEXONENAND_CMD_PI_UPDATE (0x05)
+#define FLEXONENAND_CMD_PI_ACCESS (0x66)
+#define FLEXONENAND_CMD_RECOVER_LSB (0x05)
/* NOTE: Those are not *REAL* commands */
#define ONENAND_CMD_BUFFERRAM (0x1978)
@@ -179,5 +193,6 @@
#define ONENAND_ECC_1BIT (1 << 0)
#define ONENAND_ECC_2BIT (1 << 1)
#define ONENAND_ECC_2BIT_ALL (0xAAAA)
+#define FLEXONENAND_UNCORRECTABLE_ERROR (0x1010)
#endif /* __ONENAND_REG_H */
7
10
This patch allows to have an at91 board specific lowlevel_init.S
Signed-off-by: Ilko Iliev <iliev(a)ronetix.at>
index ec6ad5d..7882e89 100644
--- a/cpu/arm926ejs/at91/lowlevel_init.S
+++ b/cpu/arm926ejs/at91/lowlevel_init.S
@@ -27,7 +27,7 @@
#include <config.h>
#include <version.h>
-#ifndef CONFIG_SKIP_LOWLEVEL_INIT
+#if !defined(CONFIG_SKIP_LOWLEVEL_INIT) &&
!defined(CONFIG_USER_LOWLEVEL_INIT)
.globl lowlevel_init
lowlevel_init:
@@ -39,5 +39,5 @@ lowlevel_init:
mov pc, lr
.ltorg
-
-#endif /* CONFIG_SKIP_LOWLEVEL_INIT */
+
+#endif /* !CONFIG_SKIP_LOWLEVEL_INIT && !CONFIG_USER_LOWLEVEL_INIT */
4
25

06 Nov '08
Update OneNAND command to support bad block awareness
Also change the OneNAND command styel like NAND
Signed-off-by: Kyungmin Park <kyungmin.park(a)samsung.com>
---
diff --git a/common/cmd_onenand.c b/common/cmd_onenand.c
index 8d87b78..1eca9b0 100644
--- a/common/cmd_onenand.c
+++ b/common/cmd_onenand.c
@@ -1,7 +1,7 @@
/*
* U-Boot command for OneNAND support
*
- * Copyright (C) 2005-2007 Samsung Electronics
+ * Copyright (C) 2005-2008 Samsung Electronics
* Kyungmin Park <kyungmin.park(a)samsung.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -18,12 +18,245 @@
#include <asm/io.h>
-extern struct mtd_info onenand_mtd;
-extern struct onenand_chip onenand_chip;
+static struct mtd_info *mtd = &onenand_mtd;
+
+static loff_t next_ofs;
+static loff_t skip_ofs;
+
+static int onenand_block_read(loff_t from, size_t len,
+ size_t *retlen, u_char *buf, int oob)
+{
+ struct onenand_chip *this = mtd->priv;
+ int blocks = (int) len >> this->erase_shift;
+ int blocksize = (1 << this->erase_shift);
+ loff_t ofs = from;
+ struct mtd_oob_ops ops = {
+ .retlen = 0,
+ };
+ int ret, dump = 0;
+
+ if (buf == NULL) {
+ buf = (u_char *) CONFIG_SYS_LOAD_ADDR;
+ dump = 1;
+ }
+
+ if (oob)
+ ops.ooblen = blocksize;
+ else
+ ops.len = blocksize;
+
+ while (blocks) {
+ ret = mtd->block_isbad(mtd, ofs);
+ if (ret) {
+ printk("Bad blocks %d at 0x%x\n", (unsigned int) ofs >> this->erase_shift, (unsigned int) ofs);
+ ofs += blocksize;
+ continue;
+ }
+
+ if (oob)
+ ops.oobbuf = buf;
+ else
+ ops.datbuf = buf;
+
+ ops.retlen = 0;
+ ret = mtd->read_oob(mtd, ofs, &ops);
+ if (ret) {
+ printk("Read failed 0x%x, %d", (unsigned int) ofs, ret);
+ mtd->block_markbad(mtd, ofs);
+ ofs += blocksize;
+ continue;
+ }
+ ofs += blocksize;
+ buf += blocksize;
+ blocks--;
+ *retlen += ops.retlen;
+
+ if (dump) {
+ int i;
+ unsigned int *p = (unsigned int *) CONFIG_SYS_LOAD_ADDR;
+ printf("Dump offset 0x%x (%d)\n", (unsigned int) ofs, (int) ofs >> this->erase_shift);
+ for (i = 0; i < 32; i++) {
+ printf("0x%08x ", *p++);
+ if (((i + 1) & (4 - 1)) == 0)
+ printf("\n");
+ }
+ buf = (u_char *) CONFIG_SYS_LOAD_ADDR;
+ }
+ }
+
+ printf("Read from 0x%x to 0x%x (%d + %d blocks)\n", (unsigned int) from, (unsigned int) ofs, (int) len >> this->erase_shift, (int) ((ofs - from) - len) >> this->erase_shift);
+
+ return 0;
+}
+
+static int onenand_block_write(loff_t to, size_t len,
+ size_t *retlen, const u_char * buf)
+{
+ struct onenand_chip *this = mtd->priv;
+ int blocks = len >> this->erase_shift;
+ int blocksize = (1 << this->erase_shift);
+ loff_t ofs;
+ size_t _retlen = 0;
+ int ret;
+
+ if (to == next_ofs) {
+ next_ofs = to + len;
+ to += skip_ofs;
+ } else {
+ next_ofs = to + len;
+ skip_ofs = 0;
+ }
+ ofs = to;
+
+ while (blocks) {
+ ret = mtd->block_isbad(mtd, ofs);
+ if (ret) {
+ printk("Bad blocks %d at 0x%x\n", (unsigned int) ofs >> this->erase_shift, (unsigned int) ofs);
+ skip_ofs += blocksize;
+ goto next;
+ }
+#ifdef USE_ERASEWRITE
+ if ((ofs & (blocksize - 1)) == 0) {
+ struct erase_info instr = {
+ .callback = NULL,
+ .addr = ofs,
+ .len = blocksize,
+ .priv = 0,
+ };
+ ret = mtd->erase(mtd, &instr);
+ if (ret) {
+ printk("Erase failed 0x%x, %d", (unsigned int) ofs, ret);
+ mtd->block_markbad(mtd, ofs);
+ skip_ofs += blocksize;
+ goto next;
+ }
+ }
+#endif
+ ret = mtd->write(mtd, ofs, blocksize, &_retlen, buf);
+ if (ret) {
+ printk("Write failed 0x%x, %d", (unsigned int) ofs, ret);
+ mtd->block_markbad(mtd, ofs);
+ skip_ofs += blocksize;
+ goto next;
+ }
+
+ buf += blocksize;
+ blocks--;
+ *retlen += _retlen;
+next:
+ ofs += blocksize;
+ }
+
+ printf("Write from 0x%x to 0x%x (%d + %d blocks)\n", (unsigned int) to, (unsigned int) ofs, (int) len >> this->erase_shift, (int) ((ofs - to) - len) >> this->erase_shift);
+
+ return 0;
+}
+
+static int onenand_block_erase(int start, int end, int force)
+{
+ struct onenand_chip *this = mtd->priv;
+ struct erase_info instr = {
+ .callback = NULL,
+ };
+ loff_t ofs;
+ int block, ret;
+ int blocksize = 1 << this->erase_shift;
+
+ for (block = start; block <= end; block++) {
+ ofs = block << this->erase_shift;
+ ret = mtd->block_isbad(mtd, ofs);
+ if (ret && !force) {
+ printf("Skip erase bad block %d at 0x%x\n", block, (unsigned int) block << this->erase_shift);
+ continue;
+ }
+
+ instr.addr = ofs;
+ instr.len = blocksize;
+ instr.priv = force;
+ ret = mtd->erase(mtd, &instr);
+ if (ret) {
+ printf("erase failed %d\n", block);
+ mtd->block_markbad(mtd, instr.addr);
+ continue;
+ }
+ }
+}
+
+static int onenand_badblocks(unsigned long start_address, unsigned long end_address)
+{
+ struct onenand_chip *this = mtd->priv;
+ struct erase_info instr = {
+ .callback = NULL,
+ .priv = 0,
+ };
+
+ int blocks;
+ loff_t ofs = 0;
+ int blocksize = 1 << this->erase_shift;
+ int start_block, end_block;
+ size_t retlen;
+ u_char *buf = (u_char *) CONFIG_SYS_LOAD_ADDR;
+ /* block size '512KiB' is enough */
+ u_char *verify_buf = (u_char *) CONFIG_SYS_LOAD_ADDR + 0x80000;
+ int ret;
+
+ start_block = start_address >> this->erase_shift;
+ end_block = end_address >> this->erase_shift;
+
+ /* Protect boot-loader from badblock testing */
+ if (start_block < 2)
+ start_block = 2;
+
+ if (end_block > (mtd->size >> this->erase_shift))
+ end_block = mtd->size >> this->erase_shift;
+
+ blocks = start_block;
+ while (blocks < end_block) {
+ ret = mtd->block_isbad(mtd, ofs);
+ if (ret) {
+ ofs += blocksize;
+ continue;
+ }
+ instr.addr = ofs;
+ instr.len = blocksize;
+ ret = mtd->erase(mtd, &instr);
+ if (ret) {
+ printk("Erase failed 0x%x, %d", (unsigned int) ofs, ret);
+ mtd->block_markbad(mtd, ofs);
+ goto next;
+ }
+ ret = mtd->write(mtd, ofs, blocksize, &retlen, buf);
+ if (ret) {
+ printk("Write failed 0x%x, %d", (unsigned int) ofs, ret);
+ mtd->block_markbad(mtd, ofs);
+ goto next;
+ }
+ ret = mtd->read(mtd, ofs, blocksize, &retlen, verify_buf);
+ if (ret) {
+ printk("Read failed 0x%x, %d", (unsigned int) ofs, ret);
+ mtd->block_markbad(mtd, ofs);
+ goto next;
+ }
+ if (memcmp(buf, verify_buf, blocksize))
+ printk("Read/Write test failed at 0x%x", (unsigned int) ofs);
+
+ printf("\rTest block at 0x%x", (unsigned int) ofs);
+
+next:
+ ofs += blocksize;
+ blocks++;
+ }
+ printf("...Done\n");
+
+ return 0;
+}
int do_onenand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
{
- int ret = 0;
+ struct onenand_chip *this = mtd->priv;
+ int blocksize = (1 << this->erase_shift);
+ ulong addr, ofs;
+ size_t len, retlen = 0;
switch (argc) {
case 0:
@@ -32,129 +265,100 @@ int do_onenand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
return 1;
case 2:
- if (strncmp(argv[1], "open", 4) == 0) {
- onenand_init();
- return 0;
- }
- printf("%s\n", onenand_mtd.name);
+ printf("%s\n", mtd->name);
return 0;
default:
/* At least 4 args */
if (strncmp(argv[1], "erase", 5) == 0) {
- struct erase_info instr = {
- .callback = NULL,
- };
- ulong start, end;
- ulong block;
- char *endtail;
+ ulong start, end, len;
+ char *endtail = NULL;
+ int force = 0;
+
+ if (strncmp(argv[1], "erasef", 6) == 0)
+ force = 1;
if (strncmp(argv[2], "block", 5) == 0) {
start = simple_strtoul(argv[3], NULL, 10);
endtail = strchr(argv[3], '-');
- end = simple_strtoul(endtail + 1, NULL, 10);
+ if (endtail)
+ end = simple_strtoul(endtail + 1, NULL, 10);
+ else
+ end = start;
} else {
- start = simple_strtoul(argv[2], NULL, 10);
- end = simple_strtoul(argv[3], NULL, 10);
+ start = simple_strtoul(argv[2], NULL, 16);
+ len = simple_strtoul(argv[3], NULL, 16);
- start >>= onenand_chip.erase_shift;
- end >>= onenand_chip.erase_shift;
+ start >>= this->erase_shift;
+ len >>= this->erase_shift;
/* Don't include the end block */
- end--;
+ end = start + len - 1;
}
if (!end || end < 0)
end = start;
- printf("Erase block from %lu to %lu\n", start, end);
+ /* Don't exceed the whole block size */
+ if (end >= mtd->size >> this->erase_shift)
+ end = (mtd->size >> this->erase_shift) - 1;
- for (block = start; block <= end; block++) {
- instr.addr = block << onenand_chip.erase_shift;
- instr.len = 1 << onenand_chip.erase_shift;
- ret = onenand_erase(&onenand_mtd, &instr);
- if (ret) {
- printf("erase failed %lu\n", block);
- break;
- }
- }
+ printf("Erase block from %lu to %lu\n", start, end);
+ onenand_block_erase(start, end, force);
return 0;
}
if (strncmp(argv[1], "read", 4) == 0) {
- ulong addr = simple_strtoul(argv[2], NULL, 16);
- ulong ofs = simple_strtoul(argv[3], NULL, 16);
- size_t len = simple_strtoul(argv[4], NULL, 16);
int oob = strncmp(argv[1], "read.oob", 8) ? 0 : 1;
- struct mtd_oob_ops ops;
-
- ops.mode = MTD_OOB_PLACE;
- if (oob) {
- ops.len = 0;
- ops.datbuf = NULL;
- ops.ooblen = len;
- ops.oobbuf = (u_char *) addr;
- } else {
- ops.len = len;
- ops.datbuf = (u_char *) addr;
- ops.ooblen = 0;
- ops.oobbuf = NULL;
- }
- ops.retlen = ops.oobretlen = 0;
+ addr = simple_strtoul(argv[2], NULL, 16);
+ ofs = simple_strtoul(argv[3], NULL, 16);
+ len = simple_strtoul(argv[4], NULL, 16);
- onenand_mtd.read_oob(&onenand_mtd, ofs, &ops);
- printf("Done\n");
+ onenand_block_read(ofs, len, &retlen, (u_char *) addr, oob);
return 0;
}
+ if (strncmp(argv[1], "badb", 4) == 0) {
+ /* Start address */
+ addr = simple_strtoul(argv[2], NULL, 16);
+ /* End address */
+ ofs = simple_strtoul(argv[3], NULL, 16);
- if (strncmp(argv[1], "write", 5) == 0) {
- ulong addr = simple_strtoul(argv[2], NULL, 16);
- ulong ofs = simple_strtoul(argv[3], NULL, 16);
- size_t len = simple_strtoul(argv[4], NULL, 16);
- size_t retlen = 0;
-
- onenand_write(&onenand_mtd, ofs, len, &retlen,
- (u_char *) addr);
- printf("Done\n");
-
- return 0;
+ return onenand_badblocks(addr, ofs);
}
- if (strncmp(argv[1], "block", 5) == 0) {
- ulong addr = simple_strtoul(argv[2], NULL, 16);
- ulong block = simple_strtoul(argv[3], NULL, 10);
- ulong page = simple_strtoul(argv[4], NULL, 10);
- size_t len = simple_strtol(argv[5], NULL, 10);
- ulong ofs;
- int oob = strncmp(argv[1], "block.oob", 9) ? 0 : 1;
- struct mtd_oob_ops ops;
-
- ops.mode = MTD_OOB_PLACE;
+ if (strncmp(argv[1], "write", 5) == 0) {
+ addr = simple_strtoul(argv[2], NULL, 16);
+ ofs = simple_strtoul(argv[3], NULL, 16);
+ len = simple_strtoul(argv[4], NULL, 16);
+ return onenand_block_write(ofs, len, &retlen, (u_char *) addr);
+ }
- ofs = block << onenand_chip.erase_shift;
- if (page)
- ofs += page << onenand_chip.page_shift;
+ if (strcmp(argv[1], "markbad") == 0) {
+ addr = (ulong)simple_strtoul(argv[2], NULL, 16);
- if (!len) {
- if (oob)
- ops.ooblen = 64;
- else
- ops.len = 512;
- }
-
- if (oob) {
- ops.datbuf = NULL;
- ops.oobbuf = (u_char *) addr;
+ int ret = mtd->block_markbad(mtd, addr);
+ if (ret == 0) {
+ printf("block 0x%08lx successfully marked as bad\n",
+ (ulong) addr);
+ return 0;
} else {
- ops.datbuf = (u_char *) addr;
- ops.oobbuf = NULL;
+ printf("block 0x%08lx NOT marked as bad! ERROR %d\n",
+ (ulong) addr, ret);
}
- ops.retlen = ops.oobretlen = 0;
+ return 1;
+ }
+
+ if (strncmp(argv[1], "dump", 4) == 0) {
+ ofs = simple_strtoul(argv[2], NULL, 16);
+ len = blocksize;
+
+ if (argc == 4)
+ len = simple_strtoul(argv[3], NULL, 16);
- onenand_read_oob(&onenand_mtd, ofs, &ops);
+ onenand_block_read(ofs, len, &retlen, NULL, 0);
return 0;
}
@@ -168,9 +372,12 @@ U_BOOT_CMD(
onenand, 6, 1, do_onenand,
"onenand - OneNAND sub-system\n",
"info - show available OneNAND devices\n"
- "onenand read[.oob] addr ofs len - read data at ofs with len to addr\n"
- "onenand write addr ofs len - write data at ofs with len from addr\n"
- "onenand erase saddr eaddr - erase block start addr to end addr\n"
- "onenand block[.oob] addr block [page] [len] - "
- "read data with (block [, page]) to addr"
+ "badb[locks] start_addr end_addr - Test & Mark bad blocks\n"
+ "onenand read[.oob] addr ofs len"
+ " - read data at ofs with len to addr\n"
+ "onenand write[.oob] addr ofs len"
+ " - write data at ofs with len from addr\n"
+ "onenand erase[force] [block] ofs len"
+ " - erase [block] at ofs with len\n"
+ "onenand markbad off - mark bad block at offset (UNSAFE)\n"
);
2
4
Hi,
We are a consulting firm that has produced a product for a client which
contains at Atmel AT91SAM9263 running linux. I have registed a machine
type at kernel.org and have ported both u-boot and the kernel to it. I
have created patches to add this support against u-boot HEAD. Is it
standard practice to submit the patches to u-boot or is it preferred
that I only make them available to the client?
--
Regards,
Jared Holzman
2
1
One more patch got added to the previous pull request.
The following changes since commit 7c84fe6a06dad9f793ed85b39b1e6c11a7882f5c:
Bartlomiej Sieka (1):
Fix to the auto-update feature documentation (CONFIG_UPDATE_TFTP_MSEC_MAX)
are available in the git repository at:
git://git.denx.de/u-boot-nand-flash.git master
Alessandro Rubini (1):
NAND: Allow NAND and OneNAND to coexist
Haiying Wang (1):
NAND: Fix CONFIG_ENV_ADDR for MPC8572DS
Jason Jin (1):
NAND: Add NAND support for MPC8536DS board
Scott Wood (1):
JFFS2: Eliminate compiler error when both NAND and OneNAND are enabled.
board/freescale/mpc8536ds/law.c | 1 +
board/freescale/mpc8536ds/tlb.c | 5 +++
fs/jffs2/jffs2_1pass.c | 12 +++----
include/configs/MPC8536DS.h | 56 ++++++++++++++++++++++++++++++-
include/configs/MPC8572DS.h | 2 +-
include/linux/mtd/nand.h | 70 +--------------------------------------
6 files changed, 67 insertions(+), 79 deletions(-)
7
14
hi frnds,
Actually i am planing to develop a boot loader for power pc board (mpc866)
of embedded planet, can any one help me out wht r the reqiurements for that.
plzzzzzzzzzzzz
2
1
Reworked MPC5121 NAND driver.
Attempted to address all the problems listed by Scott Wood.
Driver is now board independent. Will still need more
work to be SOC independent.
Driver for the NAND controller on MPC5121.
This driver has been tested on ADS5121 rev4 / MPC5121e rev2 only
which has the following configuration:
2K page size
8 bit device width
This should work on other boards with MPC5121 rev2 silicon with
little or no change to the driver.
Various vintages of this controller exist on some iMX parts.
Getting it to work on an iMX with the same controller version
should be fairly easy. More work if it is an iMX with a different
version on the controller.
This controller treats 2K pages as 4 512 byte pages
and the hw ecc is over the combined 512 byte main
area and the first 7 bytes of the spare area.
The hw ecc is stored in the last 9 bytes of the
spare area.
This all means the the spare area can not be written
separately from the main. This means unmodified JFFS2
will not work.
Signed-off-by: John Rigby <jrigby(a)freescale.com>
---
board/ads5121/ads5121.c | 16 +
drivers/mtd/nand/Makefile | 1 +
drivers/mtd/nand/fsl_nfc_nand.c | 1105 +++++++++++++++++++++++++++++++++++++++
include/configs/ads5121.h | 38 ++
4 files changed, 1160 insertions(+), 0 deletions(-)
create mode 100644 drivers/mtd/nand/fsl_nfc_nand.c
diff --git a/board/ads5121/ads5121.c b/board/ads5121/ads5121.c
index 0610928..2039f2b 100644
--- a/board/ads5121/ads5121.c
+++ b/board/ads5121/ads5121.c
@@ -24,6 +24,7 @@
#include <common.h>
#include <mpc512x.h>
#include <asm/bitops.h>
+#include <asm/io.h>
#include <command.h>
#include <asm/processor.h>
#include <fdt_support.h>
@@ -34,6 +35,7 @@
/* Clocks in use */
#define SCCR1_CLOCKS_EN (CLOCK_SCCR1_CFG_EN | \
CLOCK_SCCR1_LPC_EN | \
+ CLOCK_SCCR1_NFC_EN | \
CLOCK_SCCR1_PSC_EN(CONFIG_PSC_CONSOLE) | \
CLOCK_SCCR1_PSCFIFO_EN | \
CLOCK_SCCR1_DDR_EN | \
@@ -312,3 +314,17 @@ void ft_board_setup(void *blob, bd_t *bd)
fdt_fixup_memory(blob, (u64)bd->bi_memstart, (u64)bd->bi_memsize);
}
#endif /* defined(CONFIG_OF_LIBFDT) && defined(CONFIG_OF_BOARD_SETUP) */
+
+#if defined(CONFIG_NAND_FSL_NFC)
+void ads5121_fsl_nfc_board_cs(int chip)
+{
+ unsigned char *csreg = (unsigned char *)CFG_CPLD_BASE + 0x09;
+ u8 v;
+
+ v = in_8(csreg);
+ v |= 0xf;
+ v &= ~(1<<chip);
+
+ out_8(csreg, v);
+}
+#endif
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index b0abe6e..b010b55 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -38,6 +38,7 @@ endif
COBJS-$(CONFIG_NAND_FSL_ELBC) += fsl_elbc_nand.o
COBJS-$(CONFIG_NAND_FSL_UPM) += fsl_upm.o
COBJS-$(CONFIG_NAND_S3C64XX) += s3c64xx.o
+COBJS-$(CONFIG_NAND_FSL_NFC) += fsl_nfc_nand.o
endif
COBJS := $(COBJS-y)
diff --git a/drivers/mtd/nand/fsl_nfc_nand.c b/drivers/mtd/nand/fsl_nfc_nand.c
new file mode 100644
index 0000000..67117fe
--- /dev/null
+++ b/drivers/mtd/nand/fsl_nfc_nand.c
@@ -0,0 +1,1105 @@
+/*
+ * Copyright 2004-2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * Based on drivers/mtd/nand/mpc5121_nand.c
+ * which was based on drivers/mtd/nand/mxc_nd.c
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <common.h>
+#include <malloc.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_ecc.h>
+
+#include <asm/io.h>
+#include <nand.h>
+
+#define MIN(x, y) ((x < y) ? x : y)
+
+static struct fsl_nfc_private {
+ struct mtd_info mtd;
+ char spare_only;
+ char status_req;
+ u16 col_addr;
+ int writesize;
+ int sparesize;
+ int width;
+ int chipsel;
+} *priv;
+
+#define IS_2K_PAGE_NAND (priv->writesize == 2048)
+#define IS_4K_PAGE_NAND (priv->writesize == 4096)
+#define IS_LARGE_PAGE_NAND (priv->writesize > 512)
+
+#define NFC_REG_BASE ((void *)CONFIG_SYS_NAND_BASE)
+/*
+ * FSL NFC registers Definition
+ */
+#define NFC_BUF_ADDR (NFC_REG_BASE + 0x1E04)
+#define NFC_FLASH_ADDR (NFC_REG_BASE + 0x1E06)
+#define NFC_FLASH_CMD (NFC_REG_BASE + 0x1E08)
+#define NFC_CONFIG (NFC_REG_BASE + 0x1E0A)
+#define NFC_ECC_STATUS1 (NFC_REG_BASE + 0x1E0C)
+#define NFC_ECC_STATUS2 (NFC_REG_BASE + 0x1E0E)
+#define NFC_SPAS (NFC_REG_BASE + 0x1E10)
+#define NFC_WRPROT (NFC_REG_BASE + 0x1E12)
+#define NFC_NF_WRPRST (NFC_REG_BASE + 0x1E18)
+#define NFC_CONFIG1 (NFC_REG_BASE + 0x1E1A)
+#define NFC_CONFIG2 (NFC_REG_BASE + 0x1E1C)
+#define NFC_UNLOCKSTART_BLKADDR0 (NFC_REG_BASE + 0x1E20)
+#define NFC_UNLOCKEND_BLKADDR0 (NFC_REG_BASE + 0x1E22)
+#define NFC_UNLOCKSTART_BLKADDR1 (NFC_REG_BASE + 0x1E24)
+#define NFC_UNLOCKEND_BLKADDR1 (NFC_REG_BASE + 0x1E26)
+#define NFC_UNLOCKSTART_BLKADDR2 (NFC_REG_BASE + 0x1E28)
+#define NFC_UNLOCKEND_BLKADDR2 (NFC_REG_BASE + 0x1E2A)
+#define NFC_UNLOCKSTART_BLKADDR3 (NFC_REG_BASE + 0x1E2C)
+#define NFC_UNLOCKEND_BLKADDR3 (NFC_REG_BASE + 0x1E2E)
+
+/*!
+ * Addresses for NFC MAIN RAM BUFFER areas
+ */
+#define MAIN_AREA(n) (NFC_REG_BASE + (n)*0x200)
+
+/*!
+ * Addresses for NFC SPARE BUFFER areas
+ */
+#define SPARE_LEN 0x40
+#define SPARE_AREA(n) (NFC_REG_BASE + 0x1000 + (n)*SPARE_LEN)
+
+#define NFC_CMD 0x1
+#define NFC_ADDR 0x2
+#define NFC_INPUT 0x4
+#define NFC_OUTPUT 0x8
+#define NFC_ID 0x10
+#define NFC_STATUS 0x20
+
+/* Bit Definitions */
+#define NFC_INT (1 << 15)
+#define NFC_SP_EN (1 << 2)
+#define NFC_ECC_EN (1 << 3)
+#define NFC_INT_MSK (1 << 4)
+#define NFC_BIG (1 << 5)
+#define NFC_RST (1 << 6)
+#define NFC_CE (1 << 7)
+#define NFC_ONE_CYCLE (1 << 8)
+#define NFC_BLS_LOCKED 0
+#define NFC_BLS_LOCKED_DEFAULT 1
+#define NFC_BLS_UNLOCKED 2
+#define NFC_WPC_LOCK_TIGHT 1
+#define NFC_WPC_LOCK (1 << 1)
+#define NFC_WPC_UNLOCK (1 << 2)
+#define NFC_FLASH_ADDR_SHIFT 0
+#define NFC_UNLOCK_END_ADDR_SHIFT 0
+
+#define NFC_ECC_MODE_4 1
+/*
+ * Define delays in microsec for NAND device operations
+ */
+#define TROP_US_DELAY 2000
+
+#if defined(CONFIG_PPC)
+#define NFC_WRITEL(r, v) out_be32(r, v)
+#define NFC_WRITEW(r, v) out_be16(r, v)
+#define NFC_WRITEB(r, v) out_8(r, v)
+#define NFC_READL(r) in_be32(r)
+#define NFC_READW(r) in_be16(r)
+#define NFC_READB(r) in_8(r)
+#elif defined(CONFIG_ARM)
+#define NFC_WRITEL(r, v) writel(v, r)
+#define NFC_WRITEW(r, v) writew(v, r)
+#define NFC_WRITEB(r, v) writeb(r, v)
+#define NFC_READL(r) readl(r)
+#define NFC_READW(r) readw(r)
+#define NFC_READB(r) readb(r)
+#endif
+
+
+#ifdef CONFIG_MTD_NAND_FSL_NFC_SWECC
+static int hardware_ecc;
+#else
+static int hardware_ecc = 1;
+#endif
+
+/*
+ * OOB placement block for use with hardware ecc generation
+ */
+static struct nand_ecclayout nand_hw_eccoob_512 = {
+ .eccbytes = 9,
+ .eccpos = {
+ 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ },
+ .oobfree = {
+ {0, 5} /* byte 5 is factory bad block marker */
+ },
+};
+
+static struct nand_ecclayout nand_hw_eccoob_2k = {
+ .eccbytes = 36,
+ .eccpos = {
+ /* 9 bytes of ecc for each 512 bytes of data */
+ 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ },
+ .oobfree = {
+ {2, 5}, /* bytes 0 and 1 are factory bad block markers */
+ {16, 7},
+ {32, 7},
+ {48, 7},
+ },
+};
+
+static struct nand_ecclayout nand_hw_eccoob_4k = {
+ .eccbytes = 64, /* actually 72 but only room for 64 */
+ .eccpos = {
+ /* 9 bytes of ecc for each 512 bytes of data */
+ 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 103, 104, 105, 106, 107, 108, 109, 110, 111,
+ 119, /* 120, 121, 122, 123, 124, 125, 126, 127, */
+ },
+ .oobfree = {
+ {2, 5}, /* bytes 0 and 1 are factory bad block markers */
+ {16, 7},
+ {32, 7},
+ {48, 7},
+ {64, 7},
+ {80, 7},
+ {96, 7},
+ {112, 7},
+ },
+};
+
+static struct nand_ecclayout nand_hw_eccoob_4k_218_spare = {
+ .eccbytes = 64, /* actually 144 but only room for 64 */
+ .eccpos = {
+ /* 18 bytes of ecc for each 512 bytes of data */
+ 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 33, 34, 35, 36, 37, 38, 39, 40, 41,
+ 42, 43, 44, 45, 46, 47, 48, 49, 50,
+ 59, 60, 61, 62, 63, 64, 65, 66, 67,
+ 68, 69, 70, 71, 72, 73, 74, 75, 76,
+ 85, 86, 87, 88, 89, 90, 91, 92, 93,
+ 94, /* 95, 96, 97, 98, 99, 100, 101, 102,
+ 111, 112, 113, 114, 115, 116, 117, 118, 119,
+ 120, 121, 122, 123, 124, 125, 126, 127, 128,
+ 137, 138, 139, 140, 141, 142, 143, 144, 145,
+ 146, 147, 148, 149, 150, 151, 152, 153, 154,
+ 163, 164, 165, 166, 167, 168, 169, 170, 171,
+ 172, 173, 174, 175, 176, 177, 178, 179, 180,
+ 189, 190, 191, 192, 193, 194, 195, 196, 197,
+ 198, 199, 200, 201, 202, 203, 204, 205, 206, */
+ },
+ .oobfree = {
+ {2, 5}, /* bytes 0 and 1 are factory bad block markers */
+ {25, 8},
+ {51, 8},
+ {77, 8},
+ {103, 8},
+ {129, 8},
+ {155, 8},
+ {181, 8},
+ },
+};
+
+/*
+ * Functions to transfer data to/from spare erea.
+ */
+static void copy_from_spare(struct mtd_info *mtd, void *pbuf, int len)
+{
+ int i, copy_count, copy_size;
+
+ copy_count = mtd->writesize / 512;
+ /*
+ * Each spare area has 16 bytes for 512, 2K and normal 4K nand.
+ * For 4K nand with large 218 byte spare size, the size is 26 bytes for
+ * the first 7 buffers and 36 for the last.
+ */
+ copy_size = priv->sparesize == 218 ? 26 : 16;
+
+ for (i = 0; i < copy_count - 1 && len > 0; i++) {
+ memcpy_fromio(pbuf, SPARE_AREA(i), MIN(len, copy_size));
+ pbuf += copy_size;
+ len -= copy_size;
+ }
+ if (len > 0)
+ memcpy_fromio(pbuf, SPARE_AREA(i), len);
+}
+
+static void copy_to_spare(struct mtd_info *mtd, void *pbuf, int len)
+{
+ int i, copy_count, copy_size;
+
+ copy_count = mtd->writesize / 512;
+ /*
+ * Each spare area has 16 bytes for 512, 2K and normal 4K nand.
+ * For 4K nand with large 218 byte spare size, the size is 26 bytes for
+ * the first 7 buffers and 36 for the last.
+ */
+ copy_size = priv->sparesize == 218 ? 26 : 16;
+
+ /*
+ * Each spare area has 16 bytes for 512, 2K and normal 4K nand.
+ * For 4K nand with large 218 byte spare size, the size is 26 bytes for
+ * the first 7 buffers and 36 for the last.
+ */
+ for (i = 0; i < copy_count - 1 && len > 0; i++) {
+ memcpy_toio(SPARE_AREA(i), pbuf, MIN(len, copy_size));
+ pbuf += copy_size;
+ len -= copy_size;
+ }
+ if (len > 0)
+ memcpy_toio(SPARE_AREA(i), pbuf, len);
+}
+
+/*!
+ * This function polls the NFC to wait for the basic operation to complete by
+ * checking the INT bit of config2 register.
+ *
+ * @max_retries number of retry attempts (separated by 1 us)
+ */
+static void wait_op_done(int max_retries)
+{
+
+ while (1) {
+ max_retries--;
+ if (NFC_READW(NFC_CONFIG2) & NFC_INT)
+ break;
+ udelay(1);
+ }
+ if (max_retries <= 0)
+ MTDDEBUG(MTD_DEBUG_LEVEL0, "%s: INT not set\n", __FUNCTION__);
+}
+
+/*!
+ * This function issues the specified command to the NAND device and
+ * waits for completion.
+ *
+ * @cmds command for NAND Flash
+ */
+static void send_cmd(u16 cmd)
+{
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "send_cmd(%#x)\n", cmd);
+
+ NFC_WRITEW(NFC_FLASH_CMD, cmd);
+ NFC_WRITEW(NFC_CONFIG2, NFC_CMD);
+
+ /* Wait for operation to complete */
+ wait_op_done(TROP_US_DELAY);
+}
+
+/*!
+ * This function sends an address (or partial address) to the
+ * NAND device. The address is used to select the source/destination for
+ * a NAND command.
+ *
+ * @addr address to be written to NFC.
+ */
+static void send_addr(u16 addr)
+{
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "send_addr(%#x)\n", addr);
+ NFC_WRITEW(NFC_FLASH_ADDR, (addr << NFC_FLASH_ADDR_SHIFT));
+
+ NFC_WRITEW(NFC_CONFIG2, NFC_ADDR);
+
+ /* Wait for operation to complete */
+ wait_op_done(TROP_US_DELAY);
+}
+
+/*!
+ * This function requests the NFC to initate the transfer
+ * of data currently in the NFC RAM buffer to the NAND device.
+ *
+ * @buf_id Specify Internal RAM Buffer number (0-3)
+ */
+static void send_prog_page(u8 buf_id)
+{
+ u32 val = NFC_READW(NFC_BUF_ADDR);
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "%s\n", __FUNCTION__);
+
+ /* Set RBA bits for BUFFER val */
+ val &= ~0x7;
+ val |= buf_id;
+ NFC_WRITEW(NFC_BUF_ADDR, val);
+
+ NFC_WRITEW(NFC_CONFIG2, NFC_INPUT);
+
+ /* Wait for operation to complete */
+ wait_op_done(TROP_US_DELAY);
+}
+
+/*!
+ * This function requests the NFC to initated the transfer
+ * of data from the NAND device into in the NFC ram buffer.
+ *
+ * @buf_id Specify Internal RAM Buffer number (0-3)
+ */
+static void send_read_page(u8 buf_id)
+{
+ u32 val = NFC_READW(NFC_BUF_ADDR);
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "%s\n", __FUNCTION__);
+
+ /* Set RBA bits for BUFFER val */
+ val &= ~0x7;
+ val |= buf_id;
+ NFC_WRITEW(NFC_BUF_ADDR, val);
+
+ NFC_WRITEW(NFC_CONFIG2, NFC_OUTPUT);
+
+ /* Wait for operation to complete */
+ wait_op_done(TROP_US_DELAY);
+}
+
+/*!
+ * This function requests the NFC to perform a read of the
+ * NAND device ID.
+ */
+static void send_read_id(void)
+{
+ u32 val = NFC_READW(NFC_BUF_ADDR);
+
+ /* NFC buffer 0 is used for device ID output */
+ /* Set RBA bits for BUFFER0 */
+ val &= ~0x7;
+ NFC_WRITEW(NFC_BUF_ADDR, val);
+
+ /* Read ID into main buffer */
+ NFC_WRITEW(NFC_CONFIG2, NFC_ID);
+
+ /* Wait for operation to complete */
+ wait_op_done(TROP_US_DELAY);
+
+}
+
+/*!
+ * This function requests the NFC to perform a read of the
+ * NAND device status and returns the current status.
+ *
+ * @return device status
+ */
+static u16 get_dev_status(void)
+{
+ u32 save;
+ u16 ret;
+ u32 val;
+ /* Issue status request to NAND device */
+
+ /* save the main area1 first word, later do recovery */
+ save = NFC_READL(MAIN_AREA(1));
+ NFC_WRITEL(MAIN_AREA(1), 0);
+
+ /*
+ * NFC buffer 1 is used for device status to prevent
+ * corruption of read/write buffer on status requests.
+ */
+
+ /* Select BUFFER1 */
+ val = NFC_READW(NFC_BUF_ADDR);
+ val &= ~0x7;
+ val |= 1;
+ NFC_WRITEW(NFC_BUF_ADDR, val);
+
+ /* Read status into main buffer */
+ NFC_WRITEW(NFC_CONFIG2, NFC_STATUS);
+
+ /* Wait for operation to complete */
+ wait_op_done(TROP_US_DELAY);
+
+ /* Status is placed in first word of main buffer */
+ /* get status, then recovery area 1 data */
+ if (NFC_READW(NFC_CONFIG1) & NFC_BIG)
+ ret = NFC_READB(MAIN_AREA(1));
+ else
+ ret = NFC_READB(MAIN_AREA(1) + 3);
+
+ NFC_WRITEL(MAIN_AREA(1), save);
+ return ret;
+}
+
+/*!
+ * This functions is used by upper layer to checks if device is ready
+ *
+ * @mtd MTD structure for the NAND Flash
+ *
+ * @return 0 if device is busy else 1
+ */
+static int fsl_nfc_dev_ready(struct mtd_info *mtd)
+{
+ return 1;
+}
+
+static void fsl_nfc_enable_hwecc(struct mtd_info *mtd, int mode)
+{
+ NFC_WRITEW(NFC_CONFIG1, (NFC_READW(NFC_CONFIG1) | NFC_ECC_EN));
+ return;
+}
+
+/*
+ * Function to record the ECC corrected/uncorrected errors resulted
+ * after a page read. This NFC detects and corrects upto to 4 symbols
+ * of 9-bits each.
+ */
+static int fsl_nfc_check_ecc_status(struct mtd_info *mtd)
+{
+ u32 ecc_stat, err;
+ int no_subpages = 1;
+ int ret = 0;
+ u8 ecc_bit_mask, err_limit;
+ int is_4bit_ecc = NFC_READW(NFC_CONFIG1) & NFC_ECC_MODE_4;
+
+ ecc_bit_mask = (is_4bit_ecc ? 0x7 : 0xf);
+ err_limit = (is_4bit_ecc ? 0x4 : 0x8);
+
+ no_subpages = mtd->writesize >> 9;
+
+ ecc_stat = NFC_READW(NFC_ECC_STATUS1);
+ do {
+ err = ecc_stat & ecc_bit_mask;
+ if (err > err_limit)
+ return -1;
+ else
+ ret += err;
+ ecc_stat >>= 4;
+ } while (--no_subpages);
+
+ return ret;
+}
+
+/*!
+ * This function reads byte from the NAND Flash
+ *
+ * @mtd MTD structure for the NAND Flash
+ *
+ * @return data read from the NAND Flash
+ */
+static u_char fsl_nfc_read_byte(struct mtd_info *mtd)
+{
+ void *area_buf;
+ u_char rv;
+
+ /* Check for status request */
+ if (priv->status_req) {
+ rv = get_dev_status() & 0xff;
+ return rv;
+ }
+
+ if (priv->spare_only)
+ area_buf = SPARE_AREA(0);
+ else
+ area_buf = MAIN_AREA(0);
+
+ rv = NFC_READB(area_buf + priv->col_addr);
+ priv->col_addr++;
+ return rv;
+}
+
+/*!
+ * This function reads word from the NAND Flash
+ *
+ * @mtd MTD structure for the NAND Flash
+ *
+ * @return data read from the NAND Flash
+ */
+static u16 fsl_nfc_read_word(struct mtd_info *mtd)
+{
+ u16 rv;
+ void *area_buf;
+
+ /* If we are accessing the spare region */
+ if (priv->spare_only)
+ area_buf = SPARE_AREA(0);
+ else
+ area_buf = MAIN_AREA(0);
+
+ /* Update saved column address */
+ rv = NFC_READW(area_buf + priv->col_addr);
+ priv->col_addr += 2;
+
+ return rv;
+}
+
+/*!
+ * This function reads byte from the NAND Flash
+ *
+ * @mtd MTD structure for the NAND Flash
+ *
+ * @return data read from the NAND Flash
+ */
+static u_char fsl_nfc_read_byte16(struct mtd_info *mtd)
+{
+ /* Check for status request */
+ if (priv->status_req)
+ return (get_dev_status() & 0xff);
+
+ return fsl_nfc_read_word(mtd) & 0xff;
+}
+
+/*!
+ * This function writes data of length \b len from buffer \b buf to the NAND
+ * internal RAM buffer's MAIN area 0.
+ *
+ * @mtd MTD structure for the NAND Flash
+ * @buf data to be written to NAND Flash
+ * @len number of bytes to be written
+ */
+static void fsl_nfc_write_buf(struct mtd_info *mtd,
+ const u_char *buf, int len)
+{
+ if (priv->col_addr >= mtd->writesize || priv->spare_only) {
+ copy_to_spare(mtd, (char *)buf, len);
+ return;
+ } else {
+ priv->col_addr += len;
+ memcpy_toio(MAIN_AREA(0), (void *)buf, len);
+ }
+}
+
+/*!
+ * This function id is used to read the data buffer from the NAND Flash. To
+ * read the data from NAND Flash first the data output cycle is initiated by
+ * the NFC, which copies the data to RAMbuffer. This data of length \b len is
+ * then copied to buffer \b buf.
+ *
+ * @mtd MTD structure for the NAND Flash
+ * @buf data to be read from NAND Flash
+ * @len number of bytes to be read
+ */
+static void fsl_nfc_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+{
+
+ if (priv->col_addr >= mtd->writesize || priv->spare_only) {
+ copy_from_spare(mtd, buf, len);
+ return;
+ } else {
+ priv->col_addr += len;
+ memcpy_fromio((void *)buf, MAIN_AREA(0), len);
+ }
+}
+
+/*!
+ * This function is used by the upper layer to verify the data in NAND Flash
+ * with the data in the \b buf.
+ *
+ * @mtd MTD structure for the NAND Flash
+ * @buf data to be verified
+ * @len length of the data to be verified
+ *
+ * @return -1 if error else 0
+ *
+ */
+static int fsl_nfc_verify_buf(struct mtd_info *mtd, const u_char *buf,
+ int len)
+{
+ void *main_buf = MAIN_AREA(0);
+ /* check for 32-bit alignment? */
+ u32 *p = (u32 *) buf;
+ u32 v = 0;
+
+ for (; len > 0; len -= 4, main_buf += 4)
+ v = NFC_READL(main_buf);
+ if (v != *p++)
+ return -1;
+ return 0;
+}
+
+static int fsl_nfc_get_hw_config(struct nand_chip *this)
+{
+ immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
+ u32 rcwh;
+ int rcwh_romloc;
+ int rcwh_ps;
+ int width;
+ int writesize = 0;
+ int sparesize = 0;
+
+ /*
+ * Only support 2K for now.
+ * Remove this when others are tested and debugged.
+ */
+#if 1
+ if (CONFIG_FSL_NFC_WRITE_SIZE != 2048) {
+ printf("FSL NFC: "
+ "%d byte write size flash support is untested\n",
+ CONFIG_FSL_NFC_WRITE_SIZE);
+ return -1;
+ }
+#endif
+ rcwh = NFC_READL((void *)&(im->reset.rcwh));
+ width = ((rcwh >> 6) & 0x1) ? 2 : 1;
+
+ if (width != CONFIG_FSL_NFC_WIDTH) {
+ printf("FSL NFC: Device width mismatch, compiled for %d, "
+ "reset configuration word width is %d\n",
+ CONFIG_FSL_NFC_WIDTH, width);
+ return -1;
+ }
+
+ if (width == 2) {
+ this->options |= NAND_BUSWIDTH_16;
+ this->read_byte = fsl_nfc_read_byte16;
+ }
+
+ /*
+ * Decode the rcwh_ps and rcwh_romloc
+ * bits from reset config word
+ * to determine write size
+ */
+ rcwh_ps = (rcwh >> 7) & 0x1;
+ rcwh_romloc = (rcwh >> 21) & 0x3;
+ switch (rcwh_ps << 2 | rcwh_romloc) {
+ case 0x0:
+ case 0x1:
+ writesize = 512;
+ sparesize = 16;
+ break;
+ case 0x2:
+ case 0x3:
+ writesize = 4096;
+ sparesize = 128;
+ break;
+ case 0x4:
+ case 0x5:
+ writesize = 2048;
+ sparesize = 64;
+ break;
+ case 0x6:
+ case 0x7:
+ writesize = 4096;
+ sparesize = 218;
+ break;
+ }
+ if (CONFIG_FSL_NFC_WRITE_SIZE != writesize) {
+ printf("FSL NFC: "
+ "Device write size mismatch, "
+ "compiled for %d, "
+ "size from reset configuration word is %d\n",
+ CONFIG_FSL_NFC_WRITE_SIZE, writesize);
+ return -1;
+ }
+ if (CONFIG_FSL_NFC_SPARE_SIZE != sparesize) {
+ printf("FSL NFC: "
+ "Device spare size mismatch, "
+ "compiled for %d, "
+ "size from reset configuration word is %d\n",
+ CONFIG_FSL_NFC_SPARE_SIZE, sparesize);
+ return -1;
+ }
+
+ priv->sparesize = sparesize;
+ priv->writesize = writesize;
+ priv->width = width;
+ return 0;
+}
+
+#ifndef CONFIG_FSL_NFC_BOARD_CS_FUNC
+static void fsl_nfc_select_chip(u8 cs)
+{
+ u32 val = NFC_READW(NFC_BUF_ADDR);
+
+ val &= ~0x60;
+ val |= cs << 5;
+ NFC_WRITEW(NFC_BUF_ADDR, val);
+}
+#define CONFIG_FSL_NFC_BOARD_CS_FUNC fsl_nfc_select_chip
+#endif
+
+
+/*!
+ * This function is used by upper layer for select and deselect of the NAND
+ * chip
+ *
+ * @mtd MTD structure for the NAND Flash
+ * @chip val indicating select or deselect
+ */
+static void fsl_nfc_select_chip(struct mtd_info *mtd, int chip)
+{
+ /*
+ * This is different than the linux version.
+ * Switching between chips is done via
+ * board_nand_select_device.
+ *
+ * Only valid chip numbers here are
+ * 0 select
+ * -1 deselect
+ */
+ if (chip < -1 || chip > 0) {
+ printf("FSL NFC: "
+ "ERROR: Illegal chip select (chip = %d)\n", chip);
+ }
+
+ if (chip < 0) {
+ NFC_WRITEW(NFC_CONFIG1, (NFC_READW(NFC_CONFIG1) & ~NFC_CE));
+ return;
+ }
+
+ NFC_WRITEW(NFC_CONFIG1, (NFC_READW(NFC_CONFIG1) | NFC_CE));
+
+ /*
+ * Turn on appropriate chip.
+ */
+ CONFIG_FSL_NFC_BOARD_CS_FUNC(priv->chipsel);
+}
+
+/*
+ * Function to perform the address cycles.
+ */
+static void fsl_nfc_do_addr_cycle(struct mtd_info *mtd, int column,
+ int page_addr)
+{
+ struct nand_chip *this = mtd->priv;
+ u32 page_mask = this->pagemask;
+
+ if (column != -1) {
+ send_addr(column & 0xff);
+ /* large page nand needs an extra column addr cycle */
+ if (IS_2K_PAGE_NAND)
+ send_addr((column >> 8) & 0xf);
+ else if (IS_4K_PAGE_NAND)
+ send_addr((column >> 8) & 0x1f);
+ }
+ if (page_addr != -1) {
+ do {
+ send_addr((page_addr & 0xff));
+ page_mask >>= 8;
+ page_addr >>= 8;
+ } while (page_mask != 0);
+ }
+}
+
+/*
+ * Function to read a page from nand device.
+ */
+static void read_full_page(struct mtd_info *mtd, int page_addr)
+{
+ send_cmd(NAND_CMD_READ0);
+
+ fsl_nfc_do_addr_cycle(mtd, 0, page_addr);
+
+ if (IS_LARGE_PAGE_NAND) {
+ send_cmd(NAND_CMD_READSTART);
+ send_read_page(0);
+ } else {
+ send_read_page(0);
+ }
+}
+
+/*!
+ * This function is used by the upper layer to write command to NAND Flash for
+ * different operations to be carried out on NAND Flash
+ *
+ * @mtd MTD structure for the NAND Flash
+ * @command command for NAND Flash
+ * @column column offset for the page read
+ * @page_addr page to be read from NAND Flash
+ */
+static void fsl_nfc_command(struct mtd_info *mtd, unsigned command,
+ int column, int page_addr)
+{
+ MTDDEBUG(MTD_DEBUG_LEVEL3,
+ "fsl_nfc_command (cmd = %#x, col = %#x, page = %#x)\n",
+ command, column, page_addr);
+ /*
+ * Reset command state information
+ */
+ priv->status_req = 0;
+
+ /* Reset column address to 0 */
+ priv->col_addr = 0;
+
+ /*
+ * Command pre-processing step
+ */
+ switch (command) {
+ case NAND_CMD_STATUS:
+ priv->status_req = 1;
+ break;
+
+ case NAND_CMD_READ0:
+ priv->spare_only = 0;
+ break;
+
+ case NAND_CMD_READOOB:
+ priv->col_addr = column;
+ priv->spare_only = 1;
+ command = NAND_CMD_READ0; /* only READ0 is valid */
+ break;
+
+ case NAND_CMD_SEQIN:
+ if (column >= mtd->writesize)
+ priv->spare_only = 1;
+ else
+ priv->spare_only = 0;
+ break;
+
+ case NAND_CMD_PAGEPROG:
+ if (!priv->spare_only)
+ send_prog_page(0);
+ else
+ return;
+ break;
+
+ case NAND_CMD_ERASE1:
+ break;
+ case NAND_CMD_ERASE2:
+ break;
+ }
+
+ /*
+ * Write out the command to the device.
+ */
+ send_cmd(command);
+
+ fsl_nfc_do_addr_cycle(mtd, column, page_addr);
+
+ /*
+ * Command post-processing step
+ */
+ switch (command) {
+
+ case NAND_CMD_READOOB:
+ case NAND_CMD_READ0:
+ if (IS_LARGE_PAGE_NAND) {
+ /* send read confirm command */
+ send_cmd(NAND_CMD_READSTART);
+ /* read for each AREA */
+ send_read_page(0);
+ } else
+ send_read_page(0);
+ break;
+
+ case NAND_CMD_READID:
+ send_read_id();
+ break;
+ }
+}
+
+static int fsl_nfc_wait(struct mtd_info *mtd, struct nand_chip *chip)
+{
+ return get_dev_status();
+}
+
+static int fsl_nfc_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
+ int page, int sndcmd)
+{
+ if (sndcmd) {
+ read_full_page(mtd, page);
+ sndcmd = 0;
+ }
+
+ copy_from_spare(mtd, chip->oob_poi, mtd->oobsize);
+ return sndcmd;
+}
+
+static int fsl_nfc_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
+ int page)
+{
+ int status = 0;
+ int read_oob_col = 0;
+
+ send_cmd(NAND_CMD_READ0);
+ send_cmd(NAND_CMD_SEQIN);
+ fsl_nfc_do_addr_cycle(mtd, read_oob_col, page);
+
+ /* copy the oob data */
+ copy_to_spare(mtd, chip->oob_poi, mtd->oobsize);
+
+ send_prog_page(0);
+
+ send_cmd(NAND_CMD_PAGEPROG);
+
+ status = fsl_nfc_wait(mtd, chip);
+ if (status & NAND_STATUS_FAIL)
+ return -1;
+ return 0;
+}
+
+static int fsl_nfc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
+ uint8_t *buf)
+{
+ int stat;
+
+ stat = fsl_nfc_check_ecc_status(mtd);
+ if (stat == -1) {
+ mtd->ecc_stats.failed++;
+ printf("FSL NFC: UnCorrectable RS-ECC Error\n");
+ } else {
+ mtd->ecc_stats.corrected += stat;
+ if (stat)
+ printf("%d Symbol Correctable RS-ECC Error\n", stat);
+ }
+
+ memcpy_fromio((void *)buf, MAIN_AREA(0), mtd->writesize);
+ copy_from_spare(mtd, chip->oob_poi, mtd->oobsize);
+ return 0;
+}
+
+static void fsl_nfc_write_page(struct mtd_info *mtd,
+ struct nand_chip *chip, const uint8_t *buf)
+{
+ memcpy_toio(MAIN_AREA(0), buf, mtd->writesize);
+ copy_to_spare(mtd, chip->oob_poi, mtd->oobsize);
+}
+
+
+/*
+ * Generic flash bbt decriptors
+ */
+static uint8_t bbt_pattern[] = { 'B', 'b', 't', '0' };
+static uint8_t mirror_pattern[] = { '1', 't', 'b', 'B' };
+
+/*
+ * These are identical to the generic versions except
+ * for the offsets.
+ */
+static struct nand_bbt_descr bbt_main_descr = {
+ .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
+ | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
+ .offs = 0,
+ .len = 4,
+ .veroffs = 4,
+ .maxblocks = 4,
+ .pattern = bbt_pattern
+};
+
+static struct nand_bbt_descr bbt_mirror_descr = {
+ .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
+ | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
+ .offs = 0,
+ .len = 4,
+ .veroffs = 4,
+ .maxblocks = 4,
+ .pattern = mirror_pattern
+};
+
+void board_nand_select_device(struct nand_chip *nand, int chip)
+{
+ if (chip >= CONFIG_FSL_NFC_CHIPS) {
+ printf("FSL NFC: "
+ "ERROR: Illegal chip select (chip = %d)\n", chip);
+ return;
+ }
+ priv->chipsel = chip;
+}
+
+
+int board_nand_init(struct nand_chip *nand)
+{
+ struct mtd_info *mtd;
+
+ priv = malloc(sizeof(*priv));
+ if (!priv) {
+ printf("FSL NFC: failed to allocate priv structure\n");
+ return -1;
+ }
+ memset(priv, 0, sizeof(*priv));
+
+ if (fsl_nfc_get_hw_config(nand) < 0)
+ return -1;
+
+ mtd = &priv->mtd;
+ mtd->priv = nand;
+
+ /* 5 us command delay time */
+ nand->chip_delay = 5;
+
+ nand->dev_ready = fsl_nfc_dev_ready;
+ nand->cmdfunc = fsl_nfc_command;
+ nand->waitfunc = fsl_nfc_wait;
+ nand->select_chip = fsl_nfc_select_chip;
+ nand->options = NAND_USE_FLASH_BBT;
+ if (priv->width == 2) {
+ nand->options |= NAND_BUSWIDTH_16;
+ nand->read_byte = fsl_nfc_read_byte16;
+ }
+ nand->read_byte = fsl_nfc_read_byte;
+ nand->read_word = fsl_nfc_read_word;
+ nand->write_buf = fsl_nfc_write_buf;
+ nand->read_buf = fsl_nfc_read_buf;
+ nand->verify_buf = fsl_nfc_verify_buf;
+
+ nand->bbt_td = &bbt_main_descr;
+ nand->bbt_md = &bbt_mirror_descr;
+
+ NFC_WRITEW(NFC_CONFIG1, (NFC_READW(NFC_CONFIG1) | NFC_RST));
+
+ /* Disable interrupt */
+ NFC_WRITEW(NFC_CONFIG1, (NFC_READW(NFC_CONFIG1) | NFC_INT_MSK));
+
+ if (hardware_ecc) {
+ nand->ecc.read_page = fsl_nfc_read_page;
+ nand->ecc.write_page = fsl_nfc_write_page;
+ nand->ecc.read_oob = fsl_nfc_read_oob;
+ nand->ecc.write_oob = fsl_nfc_write_oob;
+ if (IS_2K_PAGE_NAND)
+ nand->ecc.layout = &nand_hw_eccoob_2k;
+ else if (IS_4K_PAGE_NAND)
+ if (priv->sparesize == 128)
+ nand->ecc.layout = &nand_hw_eccoob_4k;
+ else
+ nand->ecc.layout = &nand_hw_eccoob_4k_218_spare;
+ else
+ nand->ecc.layout = &nand_hw_eccoob_512;
+ /* propagate ecc.layout to mtd_info */
+ mtd->ecclayout = nand->ecc.layout;
+ nand->ecc.calculate = NULL;
+ nand->ecc.hwctl = fsl_nfc_enable_hwecc;
+ nand->ecc.correct = NULL;
+ nand->ecc.mode = NAND_ECC_HW;
+ /* RS-ECC is applied for both MAIN+SPARE not MAIN alone */
+ nand->ecc.size = 512;
+ nand->ecc.bytes = 9;
+ NFC_WRITEW(NFC_CONFIG1, (NFC_READW(NFC_CONFIG1) | NFC_ECC_EN));
+ } else {
+ nand->ecc.mode = NAND_ECC_SOFT;
+ NFC_WRITEW(NFC_CONFIG1, (NFC_READW(NFC_CONFIG1) & ~NFC_ECC_EN));
+ }
+
+ NFC_WRITEW(NFC_CONFIG1, NFC_READW(NFC_CONFIG1) & ~NFC_SP_EN);
+
+
+ /* Reset NAND */
+ nand->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
+
+ /* preset operation */
+ /* Unlock the internal RAM Buffer */
+ NFC_WRITEW(NFC_CONFIG, NFC_BLS_UNLOCKED);
+
+ /* Blocks to be unlocked */
+ NFC_WRITEW(NFC_UNLOCKSTART_BLKADDR0, 0x0);
+ NFC_WRITEW(NFC_UNLOCKEND_BLKADDR0, 0xffff);
+
+ /* Unlock Block Command for given address range */
+ NFC_WRITEW(NFC_WRPROT, NFC_WPC_UNLOCK);
+
+ /* Set sparesize */
+ NFC_WRITEW(NFC_SPAS,
+ (NFC_READW(NFC_SPAS) & 0xff00) | (priv->sparesize/2));
+
+ /*
+ * Only use 8bit ecc (aka not 4 bit) if large spare size
+ */
+ if (priv->sparesize == 218)
+ NFC_WRITEW(NFC_CONFIG1,
+ (NFC_READW(NFC_CONFIG1) & ~NFC_ECC_MODE_4));
+ else
+ NFC_WRITEW(NFC_CONFIG1,
+ (NFC_READW(NFC_CONFIG1) | NFC_ECC_MODE_4));
+
+ return 0;
+}
diff --git a/include/configs/ads5121.h b/include/configs/ads5121.h
index 8ec5e9d..d967c2e 100644
--- a/include/configs/ads5121.h
+++ b/include/configs/ads5121.h
@@ -33,6 +33,7 @@
*
* 0x0000_0000 - 0x0FFF_FFFF DDR RAM (256 MB)
* 0x3000_0000 - 0x3001_FFFF SRAM (128 KB)
+ * 0x4000_0000 - 0x400F_FFFF NFC (1 MB)
* 0x8000_0000 - 0x803F_FFFF IMMR (4 MB)
* 0x8200_0000 - 0x8200_001F CPLD (32 B)
* 0x8400_0000 - 0x82FF_FFFF PCI I/O space (16 MB)
@@ -199,6 +200,43 @@
#undef CONFIG_SYS_FLASH_CHECKSUM
/*
+ * NAND FLASH
+ * drivers/mtd/nand/mpc5121_mpc.c (rev 2 silicon/rev 4 boards only)
+ */
+#define CONFIG_NAND_FSL_NFC
+#ifdef CONFIG_NAND_FSL_NFC
+#ifdef CONFIG_NAND_SPL
+#define CONFIG_SYS_NAND_BASE 0xFFF00000
+#else
+#define CONFIG_SYS_NAND_BASE 0x40000000
+#endif
+#define CONFIG_CMD_NAND 1
+/*
+ * The flash on ADS5121 board is two flash chips in one package
+ */
+#define CONFIG_SYS_MAX_NAND_DEVICE 2
+#define NAND_MAX_CHIPS CONFIG_SYS_MAX_NAND_DEVICE
+#define CONFIG_SYS_NAND_SELECT_DEVICE 1
+#define CONFIG_NAND_MPC5121
+/*
+ * Configuration parameters for MPC5121 NAND driver
+ */
+#define CONFIG_FSL_NFC_WIDTH 1
+#define CONFIG_FSL_NFC_WRITE_SIZE 2048
+#define CONFIG_FSL_NFC_SPARE_SIZE 64
+#define CONFIG_FSL_NFC_CHIPS 2
+
+#ifndef __ASSEMBLY__
+/*
+ * ADS board as a custom chip select
+ */
+extern void ads5121_fsl_nfc_board_cs(int);
+#define CONFIG_FSL_NFC_BOARD_CS_FUNC ads5121_fsl_nfc_board_cs
+#endif /* __ASSEMBLY__ */
+#endif /* CONFIG_NAND_FSL_NFC */
+
+
+/*
* CPLD registers area is really only 32 bytes in size, but the smallest possible LP
* window is 64KB
*/
--
1.5.6.2.255.gbed62
2
2
Here's a new framework (based roughly off the linux one) for managing
MMC controllers. It handles all of the standard SD/MMC transactions,
leaving the host drivers to implement only what is necessary to
deal with their specific hardware.
We make a number of slow steps toward it before dropping it all in.
Then we add a new driver which uses it, and board support for that driver
I have no means of testing (or even compiling) the other drivers which I
mucked around with to get to this point, so I'd appreciate any testing
the pxa and atmel people could do to make sure I didn't screw them up.
It should be fairly straightforward for anyone to port those drivers to
this new framework, but as I have no means of testing them, I didn't want
to risk that kind of breakage.
5
20
I've gone through the archives a bit but still can't figure out what I'm
doing wrong.
I have a ARM board that has 128MB of DDR memory from 0x00000000 -
0x07FFFFFF.
I don't yet have flash working so I'm trying to get everything working from
DDR memory.
I connect through JTAG and download a u-boot built to be running out of
memory.
I load the u-boot image to 0x01000000. Then I put my uncompressed uImage
[1.5MB]
at address 0x04000000 (or some sufficiently high address away from
everything
else). I set the pc to 0x01000000 and resume and uBoot loads fine. No
problems
at all. So then I go to load the linux kernel and run it and this is the
output I get:
boot > printenv bootargs
bootargs=console=ttyAM0,115200
boot > bootm 04000000
## Booting image at 04000000 ...
Image Name: Linux-2.6.23.17-Pegasus
Image Type: ARM Linux Kernel Image (uncompressed)
Data Size: 1536048 Bytes = 1.5 MB
Load Address: 00008000
Entry Point: 00008000
Verifying Checksum ... OK
OK
Starting kernel ...
Uncompressing Linux..................
and that's it. It hangs there. Depending on where I put the uImage in memory
I can get the .'s to continue on for a long time before it finally stops.
But no
"OK, done" or anything. It just stops.
I've taken care to make sure things are far enough away in memory that they
shouldn't be overlapping with anything. It should just be copying the uImage
from 0x04000000 to 0x00008000 and then running it there, right? I have a
feeling it's something with the load address and entry point but those are
the
standard ones for ARM, I believe.
Just to recap:
128MB DDR Memory: 0x00000000 - 0x07FFFFFF
uBoot image: 0x01000000 ~ [162KB]
uImage: 0x04000000 ~ [1.5MB]
load address: 0x00008000
(I even have a initrd ramdisk built, but it doesn't seem to matter if I use
it or
not -- I get the same results either way.)
Thank you very much!
--
View this message in context: http://www.nabble.com/Booting-Linux-from-Memory-Hangs-tp20337037p20337037.h…
Sent from the Uboot - Users mailing list archive at Nabble.com.
1
0