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
February 2009
- 181 participants
- 548 discussions
The smc911x driver changed the naming convention for its register funcs,
so update the eeprom code accordingly.
Signed-off-by: Mike Frysinger <vapier(a)gentoo.org>
CC: Ben Warren <biggerbadderben(a)gmail.com>
---
examples/smc911x_eeprom.c | 28 +++++++++++++++-------------
1 files changed, 15 insertions(+), 13 deletions(-)
diff --git a/examples/smc911x_eeprom.c b/examples/smc911x_eeprom.c
index 3dac4d3..bf22f0a 100644
--- a/examples/smc911x_eeprom.c
+++ b/examples/smc911x_eeprom.c
@@ -59,7 +59,8 @@ static void dump_regs(void)
{
u8 i, j = 0;
for (i = 0x50; i < 0xB8; i += sizeof(u32))
- printf("%02x: 0x%08x %c", i, reg_read(CONFIG_DRIVER_SMC911X_BASE + i),
+ printf("%02x: 0x%08x %c", i,
+ smc911x_reg_read(CONFIG_DRIVER_SMC911X_BASE + i),
(j++ % 2 ? '\n' : ' '));
}
@@ -68,18 +69,18 @@ static void dump_regs(void)
*/
static int do_eeprom_cmd(int cmd, u8 reg)
{
- if (reg_read(E2P_CMD) & E2P_CMD_EPC_BUSY) {
+ if (smc911x_reg_read(E2P_CMD) & E2P_CMD_EPC_BUSY) {
printf("eeprom_cmd: busy at start (E2P_CMD = 0x%08x)\n",
- reg_read(E2P_CMD));
+ smc911x_reg_read(E2P_CMD));
return -1;
}
- reg_write(E2P_CMD, E2P_CMD_EPC_BUSY | cmd | reg);
+ smc911x_reg_write(E2P_CMD, E2P_CMD_EPC_BUSY | cmd | reg);
- while (reg_read(E2P_CMD) & E2P_CMD_EPC_BUSY)
+ while (smc911x_reg_read(E2P_CMD) & E2P_CMD_EPC_BUSY)
if (smsc_ctrlc()) {
printf("eeprom_cmd: timeout (E2P_CMD = 0x%08x)\n",
- reg_read(E2P_CMD));
+ smc911x_reg_read(E2P_CMD));
return -1;
}
@@ -92,7 +93,7 @@ static int do_eeprom_cmd(int cmd, u8 reg)
static u8 read_eeprom_reg(u8 reg)
{
int ret = do_eeprom_cmd(E2P_CMD_EPC_CMD_READ, reg);
- return (ret ? : reg_read(E2P_DATA));
+ return (ret ? : smc911x_reg_read(E2P_DATA));
}
/**
@@ -113,7 +114,7 @@ static int write_eeprom_reg(u8 value, u8 reg)
goto done;
/* write the eeprom reg */
- reg_write(E2P_DATA, value);
+ smc911x_reg_write(E2P_DATA, value);
ret = do_eeprom_cmd(E2P_CMD_EPC_CMD_WRITE, reg);
if (ret)
goto done;
@@ -184,7 +185,7 @@ static void write_stuff(char *line)
write_eeprom_reg(value, reg);
} else {
printf("Writing MAC register %02x with %08x\n", reg, value);
- reg_write(CONFIG_DRIVER_SMC911X_BASE + reg, value);
+ smc911x_reg_write(CONFIG_DRIVER_SMC911X_BASE + reg, value);
}
}
@@ -248,13 +249,14 @@ static int smc911x_init(void)
smc911x_reset();
/* Make sure we set EEDIO/EECLK to the EEPROM */
- if (reg_read(GPIO_CFG) & GPIO_CFG_EEPR_EN) {
- while (reg_read(E2P_CMD) & E2P_CMD_EPC_BUSY)
+ if (smc911x_reg_read(GPIO_CFG) & GPIO_CFG_EEPR_EN) {
+ while (smc911x_reg_read(E2P_CMD) & E2P_CMD_EPC_BUSY)
if (smsc_ctrlc()) {
- printf("init: timeout (E2P_CMD = 0x%08x)\n", reg_read(E2P_CMD));
+ printf("init: timeout (E2P_CMD = 0x%08x)\n",
+ smc911x_reg_read(E2P_CMD));
return 1;
}
- reg_write(GPIO_CFG, reg_read(GPIO_CFG) & ~GPIO_CFG_EEPR_EN);
+ smc911x_reg_write(GPIO_CFG, smc911x_reg_read(GPIO_CFG) & ~GPIO_CFG_EEPR_EN);
}
return 0;
--
1.6.1.3
2
1
This patch adds support for MLC OneNAND and Flex-OneNAND devices.
The differences are like this.
OneNAND features:
1. 2KB page
2. 64 pages per block.
3. Upto 4 writes to a page allowed.
4. 1 ECC register
5. OOB read and OOB write commands present.
MLC OneNAND has following changes against OneNAND:
1. 4KB page - both datarams are needed for a read, so no read-while-load
2. Only 1 write per page.
3. OOB read and OOB write commands absent.
Flex-OneNAND has all changes as MLC OneNAND plus some more:
1. Can configure some blocks of a die as SLC and rest as MLC
This configuration is in the form of SLC boundary which
indicates last SLC block on the die.
2. SLC blocks have 64 pages per block (block size is 256KB).
MLC blocks have 128 pages per block (block size is 512KB).
3. A single device is registered for Flex-OneNAND. This device
has erase regions. Each erase region has different block
size (either SLC or MLC).
4. 4 ECC registers.
5. LSB page recovery feature.
Signed-off-by: Rohit Hagargundgi <h.rohit(a)samsung.com>
---
drivers/mtd/onenand/onenand_base.c | 711 ++++++++++++++++++++++++++++++-----
drivers/mtd/onenand/onenand_bbt.c | 13 +-
drivers/mtd/onenand/onenand_uboot.c | 4 +-
include/linux/mtd/onenand.h | 15 +
include/linux/mtd/onenand_regs.h | 18 +-
include/onenand_uboot.h | 10 +
6 files changed, 672 insertions(+), 99 deletions(-)
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c
index 9b7bf3a..ebda48a 100644
--- a/drivers/mtd/onenand/onenand_base.c
+++ b/drivers/mtd/onenand/onenand_base.c
@@ -45,6 +45,14 @@ static const unsigned char ffchars[] = {
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 @@ static int onenand_block_address(int device, int block)
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 @@ static int onenand_bufferram_address(int device, int block)
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;
@@ -169,6 +181,91 @@ static int onenand_buffer_address(int dataram1, int sectors, int count)
}
/**
+ * flexonenand_get_block- For given address return block number and if slc
+ * @param this - OneNAND device structure
+ * @param addr - Address for which block number is needed
+ * @return isblkslc - Block is an SLC block or not
+ */
+static unsigned flexonenand_get_block(struct onenand_chip *this, loff_t addr,
+ unsigned *isblkslc)
+{
+ unsigned boundary, blk, die = 0;
+
+ 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;
+}
+
+inline unsigned onenand_get_block(struct onenand_chip *this, loff_t addr,
+ unsigned *isblkslc)
+{
+ if (!FLEXONENAND(this))
+ return addr >> this->erase_shift;
+ return flexonenand_get_block(this, addr, isblkslc);
+}
+
+/**
+ * flexonenand_get_addr - Return address of the block
+ * @this: OneNAND device structure
+ * @block: Block number on Flex-OneNAND
+ *
+ * Return address of the block
+ */
+static loff_t flexonenand_get_addr(struct onenand_chip *this, int block)
+{
+ loff_t ofs = 0;
+ int die = 0, boundary;
+
+ 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;
+}
+
+inline loff_t onenand_get_addr(struct onenand_chip *this, int block)
+{
+ if (!FLEXONENAND(this))
+ return block << this->erase_shift;
+ return flexonenand_get_addr(this, block);
+}
+
+/**
+ * flexonenand_region - [Flex-OneNAND] Return erase region of addr
+ * @param mtd MTD device structure
+ * @param addr address whose erase region needs to be identified
+ */
+inline int flexonenand_region(struct mtd_info *mtd, loff_t addr)
+{
+ int i;
+
+ for (i = 0; i < mtd->numeraseregions &&
+ addr >= mtd->eraseregions[i].offset; i++)
+ ;
+ i--;
+ return i;
+}
+
+/**
* onenand_command - [DEFAULT] Send command to OneNAND device
* @param mtd MTD device structure
* @param cmd the command to be sent
@@ -182,10 +279,12 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr,
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) {
@@ -196,16 +295,30 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr,
page = -1;
break;
+ case FLEXONENAND_CMD_PI_ACCESS:
+ /* addr contains die index */
+ block = addr * this->density_mask;
+ page = -1;
+ break;
+
case ONENAND_CMD_ERASE:
case ONENAND_CMD_BUFFERRAM:
- block = (int)(addr >> this->erase_shift);
+ block = onenand_get_block(this, addr, NULL);
page = -1;
break;
+ case FLEXONENAND_CMD_READ_PI:
+ cmd = ONENAND_CMD_READ;
+ block = addr * this->density_mask;
+ page = 0;
+ break;
+
default:
- block = (int)(addr >> this->erase_shift);
- page = (int)(addr >> this->page_shift);
+ block = onenand_get_block(this, addr, &slc);
+ page = (int) (addr - onenand_get_addr(this, block)) >> this->page_shift;
page &= this->page_mask;
+ if (slc)
+ page &= (this->page_mask >> 1);
break;
}
@@ -216,8 +329,11 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr,
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 +343,10 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr,
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 +355,10 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr,
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
+ dataram = ONENAND_SET_NEXT_BUFFERRAM(this);
break;
default:
@@ -253,14 +375,6 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr,
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 +386,28 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr,
}
/**
+ * onenand_read_ecc - return ecc status
+ * @param this onenand chip structure
+ */
+static inline int onenand_read_ecc(struct onenand_chip *this)
+{
+ int ecc, i, result = 0;
+
+ if (!FLEXONENAND(this))
+ return this->read_word(this->base + ONENAND_REG_ECC_STATUS);
+
+ for (i = 0; i < 4; i++) {
+ ecc = this->read_word(this->base + ((ONENAND_REG_ECC_STATUS + i) << 1));
+ if (likely(!ecc))
+ continue;
+ if (ecc & FLEXONENAND_UNCORRECTABLE_ERROR)
+ return ONENAND_ECC_2BIT_ALL;
+ }
+
+ 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 +431,15 @@ static int onenand_wait(struct mtd_info *mtd, int state)
ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS);
+ if (interrupt & ONENAND_INT_READ) {
+ ecc = onenand_read_ecc(this);
+ 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 +452,6 @@ static int onenand_wait(struct mtd_info *mtd, int state)
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 +569,13 @@ static int onenand_check_bufferram(struct mtd_info *mtd, loff_t addr)
struct onenand_chip *this = mtd->priv;
int block, page;
int i;
+ unsigned slc = 0;
- block = (int)(addr >> this->erase_shift);
+ block = onenand_get_block(this, addr, &slc);
page = (int)(addr >> this->page_shift);
page &= this->page_mask;
+ if (slc)
+ page &= (this->page_mask >> 1);
i = ONENAND_CURRENT_BUFFERRAM(this);
@@ -462,10 +601,13 @@ static int onenand_update_bufferram(struct mtd_info *mtd, loff_t addr,
struct onenand_chip *this = mtd->priv;
int block, page;
int i;
+ unsigned slc = 0;
- block = (int)(addr >> this->erase_shift);
+ block = onenand_get_block(this, addr, &slc);
page = (int)(addr >> this->page_shift);
page &= this->page_mask;
+ if (slc)
+ page &= (this->page_mask >> 1);
/* Invalidate BufferRAM */
for (i = 0; i < MAX_BUFFERRAM; i++) {
@@ -573,6 +715,48 @@ static int onenand_transfer_auto_oob(struct mtd_info *mtd, uint8_t *buf,
}
/**
+ * 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
+ *
+ * MLC NAND Flash cell has paired pages - LSB page and MSB page. LSB page has
+ * lower page address and MSB page has higher page address in paired pages.
+ * If power off occurs during MSB page program, the paired LSB page data can
+ * become corrupt. LSB page recovery read is a way to read LSB page though page
+ * data are corrupted. When uncorrectable error occurs as a result of LSB page
+ * read after power up, issue LSB page recovery read.
+ */
+static int onenand_recover_lsb(struct mtd_info *mtd, loff_t addr, int status)
+{
+ struct onenand_chip *this = mtd->priv;
+ unsigned slc = 0;
+
+ /* Recovery is only for Flex-OneNAND */
+ if (!FLEXONENAND(this))
+ return status;
+
+ /* 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(this, 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_INFO "onenand_recover_lsb: 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 +800,14 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
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 = ret ? onenand_recover_lsb(mtd, from, ret) : ret;
onenand_update_bufferram(mtd, from, !ret);
if (ret == -EBADMSG)
ret = 0;
@@ -636,7 +822,7 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
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 +855,15 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
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 = 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 +871,19 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
/* 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 +920,7 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from,
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 +953,20 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from,
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);
+ if (unlikely(ret))
+ ret = onenand_recover_lsb(mtd, from, ret);
+
if (ret && ret != -EBADMSG) {
printk(KERN_ERR "onenand_read_oob_nolock: read failed = 0x%x\n", ret);
break;
@@ -886,22 +1089,26 @@ static int onenand_bbt_wait(struct mtd_info *mtd, int state)
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_read_ecc(this);
+ 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 +1125,7 @@ int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from,
{
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 +1133,8 @@ int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from,
"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,11 +1154,14 @@ int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from,
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);
ret = onenand_bbt_wait(mtd, FL_READING);
+ if (unlikely(ret))
+ ret = onenand_recover_lsb(mtd, from, ret);
+
if (ret)
break;
@@ -987,9 +1199,11 @@ static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to
{
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)
@@ -1167,7 +1381,7 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,
oobbuf = this->oob_buf;
/* We send data to spare ram with oobsize
- * * to prevent byte access */
+ * to prevent byte access */
memset(oobbuf, 0xff, mtd->oobsize);
if (ops->mode == MTD_OOB_AUTO)
onenand_fill_auto_oob(mtd, oobbuf, oob, oobcolumn, thisooblen);
@@ -1236,7 +1450,7 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to,
{
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 +1494,8 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to,
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 +1511,14 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to,
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)) {
@@ -1422,34 +1645,50 @@ int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
{
struct onenand_chip *this = mtd->priv;
unsigned int block_size;
- loff_t addr;
- int len;
- int ret = 0;
-
- MTDDEBUG (MTD_DEBUG_LEVEL3,
- "onenand_erase: start = 0x%08x, len = %i\n",
- (unsigned int)instr->addr, (unsigned int)instr->len);
+ loff_t addr = instr->addr;
+ unsigned int len = instr->len;
+ int ret = 0, i;
+ struct mtd_erase_region_info *region = NULL;
+ unsigned int region_end = 0;
- block_size = (1 << this->erase_shift);
+ MTDDEBUG (MTD_DEBUG_LEVEL3, "onenand_erase: start = 0x%08x, len = %i\n",
+ (unsigned int) addr, len);
- /* Start address must align on block boundary */
- if (unlikely(instr->addr & (block_size - 1))) {
- MTDDEBUG (MTD_DEBUG_LEVEL0,
- "onenand_erase: Unaligned address\n");
+ /* Do not allow erase past end of device */
+ if (unlikely((len + addr) > mtd->size)) {
+ MTDDEBUG (MTD_DEBUG_LEVEL0, "onenand_erase: Erase past end of device\n");
return -EINVAL;
}
- /* Length must align on block boundary */
- if (unlikely(instr->len & (block_size - 1))) {
- MTDDEBUG (MTD_DEBUG_LEVEL0,
- "onenand_erase: Length not block aligned\n");
- return -EINVAL;
+ if (mtd->numeraseregions > 1) {
+ /* Find the eraseregion of this address */
+ i = flexonenand_region(mtd, addr);
+ region = &mtd->eraseregions[i];
+
+ block_size = region->erasesize;
+ region_end = region->offset + region->erasesize * region->numblocks;
+
+ /* Start address within region must align on block boundary.
+ * Erase region's start offset is always block start address.
+ */
+ if (unlikely((addr - region->offset) & (block_size - 1))) {
+ MTDDEBUG (MTD_DEBUG_LEVEL0, "onenand_erase: Unaligned address\n");
+ return -EINVAL;
+ }
+ } else {
+ block_size = 1 << this->erase_shift;
+
+ /* Start address must align on block boundary */
+ if (unlikely(addr & (block_size - 1))) {
+ MTDDEBUG (MTD_DEBUG_LEVEL0, "onenand_erase: Unaligned address\n");
+ return -EINVAL;
+ }
}
- /* Do not allow erase past end of device */
- if (unlikely((instr->len + instr->addr) > mtd->size)) {
+ /* Length must align on block boundary */
+ if (unlikely(len & (block_size - 1))) {
MTDDEBUG (MTD_DEBUG_LEVEL0,
- "onenand_erase: Erase past end of device\n");
+ "onenand_erase: Length not block aligned\n");
return -EINVAL;
}
@@ -1459,9 +1698,6 @@ int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
onenand_get_device(mtd, FL_ERASING);
/* Loop throught the pages */
- len = instr->len;
- addr = instr->addr;
-
instr->state = MTD_ERASING;
while (len) {
@@ -1481,7 +1717,7 @@ int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
else
MTDDEBUG (MTD_DEBUG_LEVEL0, "onenand_erase: "
"Failed erase, block %d\n",
- (unsigned)(addr >> this->erase_shift));
+ onenand_get_block(this, addr, NULL));
instr->state = MTD_ERASE_FAILED;
instr->fail_addr = addr;
goto erase_exit;
@@ -1489,6 +1725,22 @@ int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
len -= block_size;
addr += block_size;
+
+ if (addr == region_end) {
+ if (!len)
+ break;
+ region++;
+
+ block_size = region->erasesize;
+ region_end = region->offset + region->erasesize * region->numblocks;
+
+ if (len & (block_size - 1)) {
+ /* FIXME: This should be handled at MTD partitioning level. */
+ printk(KERN_ERR "onenand_erase: Unaligned address\n");
+ goto erase_exit;
+ }
+ }
+
}
instr->state = MTD_ERASE_DONE;
@@ -1581,8 +1833,8 @@ int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
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(this, ofs, NULL);
+ end = onenand_get_block(this, ofs + len, NULL) - 1;
/* Continuous lock scheme */
if (this->options & ONENAND_CONT_LOCK) {
@@ -1590,7 +1842,7 @@ int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
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,7 +1864,17 @@ int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
}
/* 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);
@@ -1650,15 +1912,18 @@ int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
*/
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)",
+ demuxed ? "" : "Muxed ",
+ flexonenand ? "Flex-" : "",
ddp ? "(DDP)" : "",
(16 << density), vcc ? "2.65/3.3" : "1.8", device);
@@ -1694,6 +1959,243 @@ static int onenand_check_maf(int manuf)
}
/**
+* 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, locked;
+
+ /* 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, FLEXONENAND_CMD_READ_PI, die, 0);
+ ret = this->wait(mtd, FL_READING);
+
+ bdry = this->read_word(this->base + ONENAND_DATARAM);
+ locked = bdry >> FLEXONENAND_PI_UNLOCK_SHIFT;
+ locked = (locked == 0x3) ? 0 : 1;
+ 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], locked ? "(Locked)" : "(Unlocked)");
+ }
+
+ /* Enable ECC */
+ this->write_word(syscfg, this->base + ONENAND_REG_SYS_CFG1);
+ return 0;
+}
+
+/**
+ * flexonenand_get_size - Fill up fields in onenand_chip
+ * boundary[], diesize[], mtd->size
+ * @param mtd - MTD device structure
+ */
+static void flexonenand_get_size(struct mtd_info *mtd)
+{
+ struct onenand_chip *this = mtd->priv;
+ int die, ofs, i, eraseshift, density;
+ int blksperdie, maxbdry;
+
+ density = this->device_id >> ONENAND_DEVICE_DENSITY_SHIFT;
+ density &= ONENAND_DEVICE_DENSITY_MASK;
+ blksperdie = ((16 << density) << 20) >> (this->erase_shift);
+ blksperdie >>= ONENAND_IS_DDP(this) ? 1 : 0;
+ maxbdry = blksperdie - 1;
+ eraseshift = this->erase_shift - 1;
+
+
+ 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);
+
+ for (die = 0, mtd->size = 0; die < this->dies; die++) {
+ this->diesize[die] = (blksperdie << this->erase_shift);
+ this->diesize[die] -= (this->boundary[die] + 1)
+ << (this->erase_shift - 1);
+ mtd->size += this->diesize[die];
+ }
+}
+
+/**
+ * flexonenand_check_blocks_erased - Check if blocks are erased
+ * @param mtd_info - mtd info structure
+ * @param start - first erase block to check
+ * @param end - last erase block to check
+ *
+ * Converting an unerased block from MLC to SLC
+ * causes byte values to change. Since both data and its ECC
+ * have changed, reads on the block give uncorrectable error.
+ * This might lead to the block being detected as bad.
+ *
+ * Avoid this by ensuring that the block to be converted is
+ * erased.
+ */
+static int flexonenand_check_blocks_erased(struct mtd_info *mtd, int start, int end)
+{
+ struct onenand_chip *this = mtd->priv;
+ int i, ret;
+ int block;
+ struct mtd_oob_ops ops = {
+ .mode = MTD_OOB_PLACE,
+ .ooboffs = 0,
+ .ooblen = mtd->oobsize,
+ .datbuf = NULL,
+ .oobbuf = this->oob_buf,
+ };
+ loff_t addr;
+
+ printk(KERN_DEBUG "Check blocks from %d to %d\n", start, end);
+
+ for (block = start; block <= end; block++) {
+ addr = flexonenand_get_addr(this, block);
+ if (onenand_block_isbad_nolock(mtd, addr, 0))
+ continue;
+
+ /*
+ * Since main area write results in ECC write to spare,
+ * it is sufficient to check only ECC bytes for change.
+ */
+ ret = onenand_read_oob_nolock(mtd, addr, &ops);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < mtd->oobsize; i++)
+ if (this->oob_buf[i] != 0xff)
+ break;
+
+ if (i != mtd->oobsize) {
+ printk(KERN_WARNING "Block %d not erased.\n", block);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * flexonenand_set_boundary - Writes the SLC boundary
+ * @param onenand_info - onenand info structure
+ */
+int flexonenand_set_boundary(struct mtd_info *mtd, int die,
+ int boundary, int lock)
+{
+ struct onenand_chip *this = mtd->priv;
+ int ret, density, blksperdie, old, new;
+ 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 (boundary >= blksperdie) {
+ printk(KERN_ERR "Invalid boundary value.\n");
+ return -1;
+ }
+
+ if (this->boundary[die] == boundary)
+ return -1;
+
+ /* Check if converting blocks are erased */
+ old = this->boundary[die] + (die * this->density_mask);
+ new = boundary + (die * this->density_mask);
+ ret = flexonenand_check_blocks_erased(mtd, min(old, new) + 1, max(old, new));
+ if (ret) {
+ printk(KERN_ERR "flexonenand_set_boundary: Please erase blocks before boundary change\n");
+ return ret;
+ }
+
+ printk(KERN_INFO "Changing boundary: %d%s\n", boundary, lock ?
+ "(Locked)" : "(Unlocked)");
+ boundary &= FLEXONENAND_PI_MASK;
+ boundary |= lock ? 0 : (3 << FLEXONENAND_PI_UNLOCK_SHIFT);
+
+ this->command(mtd, FLEXONENAND_CMD_PI_ACCESS, die, 0);
+ this->wait(mtd, FL_SYNCING);
+
+ this->command(mtd, ONENAND_CMD_ERASE, addr, 0);
+ ret = this->wait(mtd, FL_ERASING);
+ if (ret) {
+ printk(KERN_ERR "flexonenand_set_boundary: Failed PI erase for Die %d\n", die);
+ goto out;
+ }
+
+
+ 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 "flexonenand_set_boundary: Failed PI write for Die %d\n", die);
+ goto out;
+ }
+
+ this->command(mtd, FLEXONENAND_CMD_PI_UPDATE, die, 0);
+ ret = this->wait(mtd, FL_WRITING);
+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*/
+ flexonenand_get_size(mtd);
+
+ return ret;
+}
+
+/**
* onenand_probe - [OneNAND Interface] Probe the OneNAND device
* @param mtd MTD device structure
*
@@ -1727,42 +2229,64 @@ static int onenand_probe(struct mtd_info *mtd)
/* 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;
+ 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;
+ }
+
+ /*
+ * For Flex-OneNAND, chipsize represents maximum possible device size.
+ * mtd->size represents the actual device size.
+ */
this->chipsize = (16 << density) << 20;
/* 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;
+ /* Flex-OneNAND always has 128 pages per block */
+ mtd->erasesize <<= FLEXONENAND(this) ? 1 : 0;
this->erase_shift = ffs(mtd->erasesize) - 1;
this->page_shift = ffs(mtd->writesize) - 1;
this->ppb_shift = (this->erase_shift - this->page_shift);
this->page_mask = (mtd->erasesize / mtd->writesize) - 1;
+ /* Set density mask. it is used for DDP */
+ if (ONENAND_IS_DDP(this))
+ this->density_mask = this->chipsize >> (this->erase_shift + 1);
/* It's real page size */
this->writesize = mtd->writesize;
/* REVIST: Multichip handling */
- mtd->size = this->chipsize;
+ if (FLEXONENAND(this))
+ flexonenand_get_size(mtd);
+ else
+ mtd->size = this->chipsize;
/* Version ID */
version_id = this->read_word(this->base + ONENAND_REG_VERSION_ID);
@@ -1787,6 +2311,9 @@ static int onenand_probe(struct mtd_info *mtd)
mtd->block_isbad = onenand_block_isbad;
mtd->block_markbad = onenand_block_markbad;
+ if (FLEXONENAND(this))
+ this->options &= ~ONENAND_CONT_LOCK;
+
return 0;
}
diff --git a/drivers/mtd/onenand/onenand_bbt.c b/drivers/mtd/onenand/onenand_bbt.c
index f6092b9..3cf1758 100644
--- a/drivers/mtd/onenand/onenand_bbt.c
+++ b/drivers/mtd/onenand/onenand_bbt.c
@@ -66,6 +66,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t * buf,
struct bbm_info *bbm = this->bbm;
int i, j, numblocks, len, scanlen;
int startblock;
+ unsigned slc = 0;
loff_t from;
size_t readlen, ooblen;
struct mtd_oob_ops ops;
@@ -82,7 +83,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t * buf,
/* 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,11 @@ static int create_bbt(struct mtd_info *mtd, uint8_t * buf,
}
}
i += 2;
- from += (1 << bbm->bbt_erase_shift);
+ onenand_get_block(this, from, &slc);
+ if (slc)
+ from += (1 << bbm->bbt_erase_shift) >> 1;
+ else
+ from += (1 << bbm->bbt_erase_shift);
}
return 0;
@@ -152,7 +157,7 @@ static int onenand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt)
uint8_t res;
/* Get block number * 2 */
- block = (int)(offs >> (bbm->bbt_erase_shift - 1));
+ block = (int) (onenand_get_block(this, offs, NULL) << 1);
res = (bbm->bbt[block >> 3] >> (block & 0x06)) & 0x03;
MTDDEBUG (MTD_DEBUG_LEVEL2,
@@ -191,7 +196,7 @@ int onenand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
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
index 08082f3..419db34 100644
--- a/drivers/mtd/onenand/onenand_uboot.c
+++ b/drivers/mtd/onenand/onenand_uboot.c
@@ -31,6 +31,8 @@ void onenand_init(void)
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/linux/mtd/onenand.h b/include/linux/mtd/onenand.h
index 4467c2b..a1bb0fd 100644
--- 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,8 +44,13 @@ struct onenand_bufferram {
/**
* 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
+ * @technology [INTERN] describes the internal NAND array technology such as SLC or MLC.
+ * @density_mask: [INTERN] chip density, used for DDP devices
* @param verstion_id [INTERN] version ID
* @param options [BOARDSPECIFIC] various chip options. They can partly be set to inform onenand_scan about
* @param erase_shift [INTERN] number of address bits in a block
@@ -68,8 +74,13 @@ struct onenand_bufferram {
*/
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;
@@ -117,6 +128,8 @@ struct onenand_chip {
#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)
@@ -148,4 +161,6 @@ struct onenand_manufacturers {
int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from,
struct mtd_oob_ops *ops);
+unsigned onenand_get_block(struct onenand_chip *this, loff_t addr,
+ unsigned *isblkslc);
#endif /* __LINUX_MTD_ONENAND_H */
diff --git a/include/linux/mtd/onenand_regs.h b/include/linux/mtd/onenand_regs.h
index a245e14..34977dc 100644
--- a/include/linux/mtd/onenand_regs.h
+++ b/include/linux/mtd/onenand_regs.h
@@ -67,6 +67,9 @@
/*
* 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)
@@ -84,6 +87,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)
@@ -93,7 +101,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)
@@ -105,7 +113,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)
@@ -122,9 +130,14 @@
#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)
+#define FLEXONENAND_CMD_READ_PI (0x1985)
/*
* System Configuration 1 Register F221h (R, R/W)
@@ -185,5 +198,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 */
diff --git a/include/onenand_uboot.h b/include/onenand_uboot.h
index e960257..53754ba 100644
--- a/include/onenand_uboot.h
+++ b/include/onenand_uboot.h
@@ -21,6 +21,7 @@ struct mtd_info;
struct erase_info;
extern struct mtd_info onenand_mtd;
+extern struct onenand_chip onenand_chip;
/* Functions */
extern void onenand_init(void);
@@ -36,4 +37,13 @@ extern int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len);
extern char *onenand_print_device_info(int device);
+extern unsigned onenand_get_block(struct onenand_chip *this, loff_t addr,
+ unsigned *isblkslc);
+
+extern loff_t onenand_get_addr(struct onenand_chip *this, int block);
+
+extern int flexonenand_region(struct mtd_info *mtd, loff_t addr);
+
+extern int flexonenand_set_boundary(struct mtd_info *mtd, int die,
+ int boundary, int lock);
#endif /* __UBOOT_ONENAND_H */
--
1.5.4.3
3
4
This is the InterControl custom device based on the MPC5200B chip.
Signed-off-by: Grzegorz Bernacki <gjb(a)semihalf.com>
---
Version 6:
- adjusted kernel console variable to use PSC4
(to reflect recent DTS changes)
Version 5:
- removed unnecessary braces
- changed out32/in32 to out_be32/in_be32
Version 4:
- rebased to Ben's FEC changes
Version 3:
- updated (c)
Version 2:
- use I/O accessor functions instead of volatile pointer
- set ethernet address only if not set in environment
- add some comments and some style cleanup
MAKEALL | 1 +
Makefile | 16 ++
board/digsy_mtc/Makefile | 32 ++++
board/digsy_mtc/config.mk | 24 +++
board/digsy_mtc/digsy_mtc.c | 331 ++++++++++++++++++++++++++++++++++++
board/digsy_mtc/eeprom.h | 32 ++++
board/digsy_mtc/is42s16800a-7t.h | 28 +++
cpu/mpc5xxx/ide.c | 2 +-
include/configs/digsy_mtc.h | 346 ++++++++++++++++++++++++++++++++++++++
9 files changed, 811 insertions(+), 1 deletions(-)
create mode 100644 board/digsy_mtc/Makefile
create mode 100644 board/digsy_mtc/config.mk
create mode 100644 board/digsy_mtc/digsy_mtc.c
create mode 100644 board/digsy_mtc/eeprom.h
create mode 100644 board/digsy_mtc/is42s16800a-7t.h
create mode 100644 include/configs/digsy_mtc.h
diff --git a/MAKEALL b/MAKEALL
index cf05133..cd64823 100755
--- a/MAKEALL
+++ b/MAKEALL
@@ -47,6 +47,7 @@ LIST_5xxx=" \
BC3450 \
cm5200 \
cpci5200 \
+ digsy_mtc \
EVAL5200 \
fo300 \
icecube_5100 \
diff --git a/Makefile b/Makefile
index 787c5f2..424b0d9 100644
--- a/Makefile
+++ b/Makefile
@@ -527,6 +527,22 @@ cm5200_config: unconfig
cpci5200_config: unconfig
@$(MKCONFIG) -a cpci5200 ppc mpc5xxx cpci5200 esd
+digsy_mtc_config \
+digsy_mtc_LOWBOOT_config \
+digsy_mtc_RAMBOOT_config: unconfig
+ @mkdir -p $(obj)include
+ @mkdir -p $(obj)board/digsy_mtc
+ @ >$(obj)include/config.h
+ @[ -z "$(findstring LOWBOOT_,$@)" ] || \
+ { echo "TEXT_BASE = 0xFF000000" >$(obj)board/digsy_mtc/config.tmp ; \
+ echo "... with LOWBOOT configuration" ; \
+ }
+ @[ -z "$(findstring RAMBOOT_,$@)" ] || \
+ { echo "TEXT_BASE = 0x00100000" >$(obj)board/digsy_mtc/config.tmp ; \
+ echo "... with RAMBOOT configuration" ; \
+ }
+ @$(MKCONFIG) -a digsy_mtc ppc mpc5xxx digsy_mtc
+
hmi1001_config: unconfig
@$(MKCONFIG) hmi1001 ppc mpc5xxx hmi1001
diff --git a/board/digsy_mtc/Makefile b/board/digsy_mtc/Makefile
new file mode 100644
index 0000000..7d659e5
--- /dev/null
+++ b/board/digsy_mtc/Makefile
@@ -0,0 +1,32 @@
+
+#
+# Author: Grzegorz Bernacki, Semihalf, gjb(a)semihalf.com
+#
+
+include $(TOPDIR)/config.mk
+
+LIB = $(obj)lib$(BOARD).a
+
+COBJS := $(BOARD).o
+
+SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS := $(addprefix $(obj),$(COBJS))
+SOBJS := $(addprefix $(obj),$(SOBJS))
+
+$(LIB): $(obj).depend $(OBJS)
+ $(AR) $(ARFLAGS) $@ $(OBJS)
+
+clean:
+ rm -f $(SOBJS) $(OBJS)
+
+distclean: clean
+ rm -f $(LIB) core *.bak .depend
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/board/digsy_mtc/config.mk b/board/digsy_mtc/config.mk
new file mode 100644
index 0000000..e2f14b0
--- /dev/null
+++ b/board/digsy_mtc/config.mk
@@ -0,0 +1,24 @@
+#
+# Author: Grzegorz Bernacki, Semihalf, gjb(a)semihalf.com
+#
+
+#
+# digsyMTC board:
+#
+# Valid values for TEXT_BASE are:
+#
+# 0xFFF00000 boot high (standard configuration)
+# 0xFE000000 boot low
+# 0x00100000 boot from RAM (for testing only)
+#
+
+sinclude $(OBJTREE)/board/$(BOARDDIR)/config.tmp
+
+ifndef TEXT_BASE
+## Standard: boot high
+TEXT_BASE = 0xFFF00000
+## For testing: boot from RAM
+# TEXT_BASE = 0x00100000
+endif
+
+PLATFORM_CPPFLAGS += -DTEXT_BASE=$(TEXT_BASE) -I$(TOPDIR)/board
diff --git a/board/digsy_mtc/digsy_mtc.c b/board/digsy_mtc/digsy_mtc.c
new file mode 100644
index 0000000..7b94771
--- /dev/null
+++ b/board/digsy_mtc/digsy_mtc.c
@@ -0,0 +1,331 @@
+/*
+ * (C) Copyright 2003
+ * Wolfgang Denk, DENX Software Engineering, wd(a)denx.de.
+ *
+ * (C) Copyright 2004
+ * Mark Jonas, Freescale Semiconductor, mark.jonas(a)motorola.com.
+ *
+ * (C) Copyright 2005-2009
+ * Modified for InterControl digsyMTC MPC5200 board by
+ * Frank Bodammer, GCD Hard- & Software GmbH,
+ * frank.bodammer(a)gcd-solutions.de
+ *
+ * (C) Copyright 2009
+ * Grzegorz Bernacki, Semihalf, gjb(a)semihalf.com
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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
+ */
+
+#include <common.h>
+#include <mpc5xxx.h>
+#include <pci.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <i2c.h>
+#include "eeprom.h"
+#include "is42s16800a-7t.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+extern int usb_cpu_init(void);
+
+#ifndef CONFIG_SYS_RAMBOOT
+static void sdram_start(int hi_addr)
+{
+ long hi_addr_bit = hi_addr ? 0x01000000 : 0;
+ long control = SDRAM_CONTROL | hi_addr_bit;
+
+ /* unlock mode register */
+ out_be32((void *)MPC5XXX_SDRAM_CTRL, control | 0x80000000);
+
+ /* precharge all banks */
+ out_be32((void *)MPC5XXX_SDRAM_CTRL, control | 0x80000002);
+
+ /* auto refresh */
+ out_be32((void *)MPC5XXX_SDRAM_CTRL, control | 0x80000004);
+
+ /* set mode register */
+ out_be32((void *)MPC5XXX_SDRAM_MODE, SDRAM_MODE);
+
+ /* normal operation */
+ out_be32((void *)MPC5XXX_SDRAM_CTRL, control);
+}
+#endif
+
+/*
+ * ATTENTION: Although partially referenced initdram does NOT make real use
+ * use of CONFIG_SYS_SDRAM_BASE. The code does not work if
+ * CONFIG_SYS_SDRAM_BASE is something else than 0x00000000.
+ */
+
+phys_size_t initdram(int board_type)
+{
+ ulong dramsize = 0;
+ ulong dramsize2 = 0;
+ uint svr, pvr;
+#ifndef CONFIG_SYS_RAMBOOT
+ ulong test1, test2;
+
+ /* setup SDRAM chip selects */
+ out_be32((void *)MPC5XXX_SDRAM_CS0CFG, 0x0000001C); /* 512MB at 0x0 */
+ out_be32((void *)MPC5XXX_SDRAM_CS1CFG, 0x80000000); /* disabled */
+
+ /* setup config registers */
+ out_be32((void *)MPC5XXX_SDRAM_CONFIG1, SDRAM_CONFIG1);
+ out_be32((void *)MPC5XXX_SDRAM_CONFIG2, SDRAM_CONFIG2);
+
+ /* find RAM size using SDRAM CS0 only */
+ sdram_start(0);
+ test1 = get_ram_size((long *)CONFIG_SYS_SDRAM_BASE, 0x08000000);
+ sdram_start(1);
+ test2 = get_ram_size((long *)CONFIG_SYS_SDRAM_BASE, 0x08000000);
+ if (test1 > test2) {
+ sdram_start(0);
+ dramsize = test1;
+ } else {
+ dramsize = test2;
+ }
+
+ /* memory smaller than 1MB is impossible */
+ if (dramsize < (1 << 20))
+ dramsize = 0;
+
+ /* set SDRAM CS0 size according to the amount of RAM found */
+ if (dramsize > 0) {
+ out_be32((void *)MPC5XXX_SDRAM_CS0CFG,
+ (0x13 + __builtin_ffs(dramsize >> 20) - 1));
+ } else {
+ out_be32((void *)MPC5XXX_SDRAM_CS0CFG, 0); /* disabled */
+ }
+
+ /* let SDRAM CS1 start right after CS0 */
+ out_be32((void *)MPC5XXX_SDRAM_CS1CFG, dramsize + 0x0000001C);
+
+ /* find RAM size using SDRAM CS1 only */
+ test1 = get_ram_size((long *)(CONFIG_SYS_SDRAM_BASE + dramsize),
+ 0x08000000);
+ dramsize2 = test1;
+
+ /* memory smaller than 1MB is impossible */
+ if (dramsize2 < (1 << 20))
+ dramsize2 = 0;
+
+ /* set SDRAM CS1 size according to the amount of RAM found */
+ if (dramsize2 > 0) {
+ out_be32((void *)MPC5XXX_SDRAM_CS1CFG, (dramsize |
+ (0x13 + __builtin_ffs(dramsize2 >> 20) - 1)));
+ } else {
+ out_be32((void *)MPC5XXX_SDRAM_CS1CFG, dramsize); /* disabled */
+ }
+
+#else /* CONFIG_SYS_RAMBOOT */
+
+ /* retrieve size of memory connected to SDRAM CS0 */
+ dramsize = in_be32((void *)MPC5XXX_SDRAM_CS0CFG) & 0xFF;
+ if (dramsize >= 0x13)
+ dramsize = (1 << (dramsize - 0x13)) << 20;
+ else
+ dramsize = 0;
+
+ /* retrieve size of memory connected to SDRAM CS1 */
+ dramsize2 = in_be32((void *)MPC5XXX_SDRAM_CS1CFG) & 0xFF;
+ if (dramsize2 >= 0x13)
+ dramsize2 = (1 << (dramsize2 - 0x13)) << 20;
+ else
+ dramsize2 = 0;
+
+#endif /* CONFIG_SYS_RAMBOOT */
+
+ /*
+ * On MPC5200B we need to set the special configuration delay in the
+ * DDR controller. Please refer to Freescale's AN3221 "MPC5200B SDRAM
+ * Initialization and Configuration", 3.3.1 SDelay--MBAR + 0x0190:
+ *
+ * "The SDelay should be written to a value of 0x00000004. It is
+ * required to account for changes caused by normal wafer processing
+ * parameters."
+ */
+ svr = get_svr();
+ pvr = get_pvr();
+ if ((SVR_MJREV(svr) >= 2) &&
+ (PVR_MAJ(pvr) == 1) && (PVR_MIN(pvr) == 4))
+ out_be32((void *)MPC5XXX_SDRAM_SDELAY, 0x04);
+
+ return dramsize + dramsize2;
+}
+
+int checkboard(void)
+{
+ char *s = getenv("serial#");
+
+ puts ("Board: InterControl digsyMTC");
+ if (s != NULL) {
+ puts(", ");
+ puts(s);
+ }
+ putc('\n');
+
+ return 0;
+}
+
+int board_early_init_r(void)
+{
+ /*
+ * Now, when we are in RAM, enable flash write access for detection
+ * process. Note that CS_BOOT cannot be cleared when executing in
+ * flash.
+ */
+ /* disable CS_BOOT */
+ out_be32((void *)MPC5XXX_ADDECR,
+ in_be32((void *)MPC5XXX_ADDECR) & ~(1 << 25));
+ /* enable CS1 */
+ out_be32((void *)MPC5XXX_ADDECR,
+ in_be32((void *)MPC5XXX_ADDECR) | (1 << 17));
+ /* enable CS0 */
+ out_be32((void *)MPC5XXX_ADDECR,
+ in_be32((void *)MPC5XXX_ADDECR) | (1 << 16));
+
+#if defined(CONFIG_USB_OHCI_NEW) && defined(CONFIG_SYS_USB_OHCI_CPU_INIT)
+ /* Low level USB init, required for proper kernel operation */
+ usb_cpu_init();
+#endif
+ return (0);
+}
+
+void static set_ethaddr(void)
+{
+ char str_eth_addr[20];
+ uchar eth_addr[6];
+ ulong n;
+ ushort read = 0;
+ ushort addr = 0;
+ ushort chip = 0;
+ ushort addr_of_eth_addr = 0;
+ ushort len_sys = 0;
+ ushort len_sys_cfg = 0;
+
+ /* check identification word */
+ i2c_read(EEPROM_ADDR, EEPROM_ADDR_IDENT, 1, (uchar *)&read, 2);
+ if (read != EEPROM_IDENT)
+ return;
+
+ /* calculate offset of config area */
+ i2c_read(EEPROM_ADDR, EEPROM_ADDR_LEN_SYS, 1, (uchar *)&len_sys, 2);
+ i2c_read(EEPROM_ADDR, EEPROM_ADDR_LEN_SYSCFG, 1,
+ (uchar *)&len_sys_cfg, 2);
+ addr_of_eth_addr = (len_sys + len_sys_cfg + EEPROM_ADDR_ETHADDR) << 1;
+ if (addr_of_eth_addr >= EEPROM_LEN)
+ return;
+
+ for (n = 0; n < 6 ; n++) {
+ addr = addr_of_eth_addr + n;
+ chip = EEPROM_ADDR + ((addr & 0x300)>>8);
+ i2c_read(chip, (addr & 0xFF), 1, (uchar *)ð_addr[n], 1);
+ }
+
+ sprintf(str_eth_addr, "%02X:%02X:%02X:%02X:%02X:%02X",
+ eth_addr[0], eth_addr[1], eth_addr[2],
+ eth_addr[3], eth_addr[4], eth_addr[5]);
+ setenv("ethaddr", str_eth_addr);
+}
+
+int last_stage_init (void)
+{
+ if (getenv("ethaddr") == NULL)
+ set_ethaddr();
+ return 0;
+}
+
+#ifdef CONFIG_PCI
+static struct pci_controller hose;
+
+extern void pci_mpc5xxx_init(struct pci_controller *);
+
+void pci_init_board(void)
+{
+ pci_mpc5xxx_init(&hose);
+}
+#endif
+
+#ifdef CONFIG_CMD_IDE
+
+#ifdef CONFIG_IDE_RESET
+
+void init_ide_reset(void)
+{
+ debug ("init_ide_reset\n");
+
+ /* set gpio output value to 1 */
+ out_be32((void *)MPC5XXX_WU_GPIO_DATA_O,
+ in_be32((void *)MPC5XXX_WU_GPIO_DATA_O) | (1 << 25));
+ /* open drain output */
+ out_be32((void *)MPC5XXX_WU_GPIO_ODE,
+ in_be32((void *)MPC5XXX_WU_GPIO_ODE) | (1 << 25));
+ /* direction output */
+ out_be32((void *)MPC5XXX_WU_GPIO_DIR,
+ in_be32((void *)MPC5XXX_WU_GPIO_DIR) | (1 << 25));
+ /* enable gpio */
+ out_be32((void *)MPC5XXX_WU_GPIO_ENABLE,
+ in_be32((void *)MPC5XXX_WU_GPIO_ENABLE) | (1 << 25));
+
+}
+
+void ide_set_reset(int idereset)
+{
+ debug ("ide_reset(%d)\n", idereset);
+
+ /* set gpio output value to 0 */
+ out_be32((void *)MPC5XXX_WU_GPIO_DATA_O,
+ in_be32((void *)MPC5XXX_WU_GPIO_DATA_O) & ~(1 << 25));
+ /* open drain output */
+ out_be32((void *)MPC5XXX_WU_GPIO_ODE,
+ in_be32((void *)MPC5XXX_WU_GPIO_ODE) | (1 << 25));
+ /* direction output */
+ out_be32((void *)MPC5XXX_WU_GPIO_DIR,
+ in_be32((void *)MPC5XXX_WU_GPIO_DIR) | (1 << 25));
+ /* enable gpio */
+ out_be32((void *)MPC5XXX_WU_GPIO_ENABLE,
+ in_be32((void *)MPC5XXX_WU_GPIO_ENABLE) | (1 << 25));
+
+ udelay(10000);
+
+ /* set gpio output value to 1 */
+ out_be32((void *)MPC5XXX_WU_GPIO_DATA_O,
+ in_be32((void *)MPC5XXX_WU_GPIO_DATA_O) | (1 << 25));
+ /* open drain output */
+ out_be32((void *)MPC5XXX_WU_GPIO_ODE,
+ in_be32((void *)MPC5XXX_WU_GPIO_ODE) | (1 << 25));
+ /* direction output */
+ out_be32((void *)MPC5XXX_WU_GPIO_DIR,
+ in_be32((void *)MPC5XXX_WU_GPIO_DIR) | (1 << 25));
+ /* enable gpio */
+ out_be32((void *)MPC5XXX_WU_GPIO_ENABLE,
+ in_be32((void *)MPC5XXX_WU_GPIO_ENABLE) | (1 << 25));
+}
+#endif /* CONFIG_IDE_RESET */
+
+#if defined(CONFIG_OF_LIBFDT) && defined(CONFIG_OF_BOARD_SETUP)
+void ft_board_setup(void *blob, bd_t *bd)
+{
+ ft_cpu_setup(blob, bd);
+}
+#endif /* defined(CONFIG_OF_LIBFDT) && defined(CONFIG_OF_BOARD_SETUP) */
+
+#endif /* CONFIG_CMD_IDE */
+
diff --git a/board/digsy_mtc/eeprom.h b/board/digsy_mtc/eeprom.h
new file mode 100644
index 0000000..39e0378
--- /dev/null
+++ b/board/digsy_mtc/eeprom.h
@@ -0,0 +1,32 @@
+/*
+ * (C) Copyright 2009 Semihalf.
+ * Written by: Grzegorz Bernacki <gjb(a)semihalf.com>
+ *
+ * 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 anty 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 CMD_EEPROM_H
+#define CMD_EEPROM_H
+
+#define EEPROM_ADDR CONFIG_SYS_I2C_EEPROM_ADDR
+#define EEPROM_LEN 1024 /* eeprom length */
+#define EEPROM_IDENT 2408 /* identification word */
+#define EEPROM_ADDR_IDENT 0 /* identification word offset */
+#define EEPROM_ADDR_LEN_SYS 2 /* system area lenght offset */
+#define EEPROM_ADDR_LEN_SYSCFG 4 /* system config area length offset */
+#define EEPROM_ADDR_ETHADDR 23 /* ethernet addres offset */
+
+#endif
diff --git a/board/digsy_mtc/is42s16800a-7t.h b/board/digsy_mtc/is42s16800a-7t.h
new file mode 100644
index 0000000..1873ea7
--- /dev/null
+++ b/board/digsy_mtc/is42s16800a-7t.h
@@ -0,0 +1,28 @@
+/*
+ * (C) Copyright 2004-2009
+ * Mark Jonas, Freescale Semiconductor, mark.jonas(a)motorola.com.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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
+ */
+
+#define SDRAM_MODE 0x00CD0000
+#define SDRAM_CONTROL 0x505F0000
+#define SDRAM_CONFIG1 0xD2322900
+#define SDRAM_CONFIG2 0x8AD70000
+
diff --git a/cpu/mpc5xxx/ide.c b/cpu/mpc5xxx/ide.c
index df5b4ac..88da199 100644
--- a/cpu/mpc5xxx/ide.c
+++ b/cpu/mpc5xxx/ide.c
@@ -42,7 +42,7 @@ int ide_preinit (void)
struct mpc5xxx_sdma *psdma = (struct mpc5xxx_sdma *) MPC5XXX_SDMA;
reg = *(vu_long *) MPC5XXX_GPS_PORT_CONFIG;
-#if defined(CONFIG_TOTAL5200)
+#if defined(CONFIG_TOTAL5200) || defined(CONFIG_DIGSY_MTC)
/* ATA cs0/1 on i2c2 clk/io */
reg = (reg & ~0x03000000ul) | 0x02000000ul;
#else
diff --git a/include/configs/digsy_mtc.h b/include/configs/digsy_mtc.h
new file mode 100644
index 0000000..8945050
--- /dev/null
+++ b/include/configs/digsy_mtc.h
@@ -0,0 +1,346 @@
+/*
+ * (C) Copyright 2003-2004
+ * Wolfgang Denk, DENX Software Engineering, wd(a)denx.de.
+ *
+ * (C) Copyright 2005-2007
+ * Modified for InterControl digsyMTC MPC5200 board by
+ * Frank Bodammer, GCD Hard- & Software GmbH,
+ * frank.bodammer(a)gcd-solutions.de
+ *
+ * (C) Copyright 2009 Semihalf
+ * Optimized for digsyMTC by: Grzegorz Bernacki <gjb(a)semihalf.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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 __CONFIG_H
+#define __CONFIG_H
+
+/*
+ * High Level Configuration Options
+ */
+
+#define CONFIG_MPC5xxx 1 /* This is an MPC5xxx CPU */
+#define CONFIG_MPC5200 1 /* (more precisely an MPC5200 CPU) */
+#define CONFIG_DIGSY_MTC 1 /* ... on InterControl digsyMTC board */
+
+#define CONFIG_SYS_MPC5XXX_CLKIN 33000000
+
+#define BOOTFLAG_COLD 0x01
+#define BOOTFLAG_WARM 0x02
+
+#define CONFIG_SYS_CACHELINE_SIZE 32
+
+/*
+ * Serial console configuration
+ */
+#define CONFIG_PSC_CONSOLE 4 /* console is on PSC4 */
+#define CONFIG_BAUDRATE 115200 /* ... at 115200 bps */
+#define CONFIG_SYS_BAUDRATE_TABLE \
+ { 9600, 19200, 38400, 57600, 115200, 230400 }
+
+/*
+ * PCI Mapping:
+ * 0x40000000 - 0x4fffffff - PCI Memory
+ * 0x50000000 - 0x50ffffff - PCI IO Space
+ */
+#define CONFIG_PCI 1
+#define CONFIG_PCI_PNP 1
+#define CONFIG_PCI_SCAN_SHOW 1
+
+#define CONFIG_PCI_MEM_BUS 0x40000000
+#define CONFIG_PCI_MEM_PHYS CONFIG_PCI_MEM_BUS
+#define CONFIG_PCI_MEM_SIZE 0x10000000
+
+#define CONFIG_PCI_IO_BUS 0x50000000
+#define CONFIG_PCI_IO_PHYS CONFIG_PCI_IO_BUS
+#define CONFIG_PCI_IO_SIZE 0x01000000
+
+/*
+ * Partitions
+ */
+#define CONFIG_DOS_PARTITION
+#define CONFIG_BZIP2
+
+/*
+ * Command line configuration.
+ */
+#include <config_cmd_default.h>
+
+#define CONFIG_CMD_DFL
+#define CONFIG_CMD_CACHE
+#define CONFIG_CMD_DATE
+#define CONFIG_CMD_DHCP
+#define CONFIG_CMD_DIAG
+#define CONFIG_CMD_EEPROM
+#define CONFIG_CMD_ELF
+#define CONFIG_CMD_EXT2
+#define CONFIG_CMD_FAT
+#define CONFIG_CMD_I2C
+#define CONFIG_CMD_IDE
+#define CONFIG_CMD_IRQ
+#define CONFIG_CMD_MII
+#define CONFIG_CMD_PCI
+#define CONFIG_CMD_PING
+#define CONFIG_CMD_REGINFO
+#define CONFIG_CMD_SAVES
+#define CONFIG_CMD_USB
+
+#if (TEXT_BASE == 0xFF000000)
+#define CONFIG_SYS_LOWBOOT 1
+#endif
+
+/*
+ * Autobooting
+ */
+#define CONFIG_BOOTDELAY 1
+
+#undef CONFIG_BOOTARGS
+
+#define CONFIG_EXTRA_ENV_SETTINGS \
+ "netdev=eth0\0" \
+ "console=ttyPSC0\0" \
+ "kernel_addr_r=400000\0" \
+ "fdt_addr_r=600000\0" \
+ "nfsargs=setenv bootargs root=/dev/nfs rw " \
+ "nfsroot=${serverip}:${rootpath}\0" \
+ "addip=setenv bootargs ${bootargs} " \
+ "ip=${ipaddr}:${serverip}:${gatewayip}:"\
+ "${netmask}:${hostname}:${netdev}:off panic=1\0" \
+ "addcons=setenv bootargs ${bootargs} console=${console},${baudrate}\0"\
+ "rootpath=/opt/eldk/ppc_6xx\0" \
+ "net_nfs=tftp ${kernel_addr_r} ${bootfile};" \
+ "tftp ${fdt_addr_r} ${fdt_file};" \
+ "run nfsargs addip addcons;" \
+ "bootm ${kernel_addr_r} - ${fdt_addr_r}\0" \
+ "load=tftp 200000 ${u-boot}\0" \
+ "update=protect off FFF00000 +${filesize};" \
+ "erase FFF00000 +${filesize};" \
+ "cp.b 200000 FFF00000 ${filesize};" \
+ "protect on FFF00000 +${filesize}\0" \
+ ""
+
+/*
+ * I2C configuration
+ */
+#define CONFIG_HARD_I2C 1
+#define CONFIG_SYS_I2C_MODULE 1
+#define CONFIG_SYS_I2C_SPEED 100000
+#define CONFIG_SYS_I2C_SLAVE 0x7F
+
+/*
+ * EEPROM configuration
+ */
+#define CONFIG_SYS_I2C_EEPROM_ADDR 0x50 /* 1010000x */
+#define CONFIG_SYS_I2C_EEPROM_ADDR_LEN 1
+#define CONFIG_SYS_EEPROM_PAGE_WRITE_BITS 3
+#define CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS 70
+
+/*
+ * RTC configuration
+ */
+#define CONFIG_RTC_DS1337
+#define CONFIG_SYS_I2C_RTC_ADDR 0x68
+
+/*
+ * Flash configuration
+ */
+#define CONFIG_SYS_FLASH_CFI 1
+#define CONFIG_FLASH_CFI_DRIVER 1
+
+#define CONFIG_SYS_FLASH_BASE 0xFF000000
+#define CONFIG_SYS_FLASH_SIZE 0x01000000
+
+#define CONFIG_SYS_MAX_FLASH_BANKS 1
+#define CONFIG_SYS_MAX_FLASH_SECT 256
+#define CONFIG_FLASH_16BIT
+#define CONFIG_SYS_FLASH_CFI_WIDTH FLASH_CFI_16BIT
+#define CONFIG_SYS_FLASH_BANKS_LIST { CONFIG_SYS_FLASH_BASE }
+#define CONFIG_SYS_FLASH_ERASE_TOUT 240000
+#define CONFIG_SYS_FLASH_WRITE_TOUT 500
+
+#define CONFIG_OF_LIBFDT 1
+#define CONFIG_OF_BOARD_SETUP 1
+
+#define OF_CPU "PowerPC,5200@0"
+#define OF_SOC "soc5200@f0000000"
+#define OF_TBCLK (bd->bi_busfreq / 4)
+
+#define CONFIG_BOARD_EARLY_INIT_R
+/*
+ * Environment settings
+ */
+
+#define CONFIG_ENV_IS_IN_FLASH 1
+#if defined(CONFIG_LOWBOOT)
+#define CONFIG_ENV_ADDR 0xFF060000
+#else /* CONFIG_LOWBOOT */
+#define CONFIG_ENV_ADDR 0xFFF60000
+#endif /* CONFIG_LOWBOOT */
+#define CONFIG_ENV_SIZE 0x10000
+#define CONFIG_ENV_SECT_SIZE 0x20000
+#define CONFIG_ENV_OVERWRITE 1
+
+/*
+ * Memory map
+ */
+#define CONFIG_SYS_MBAR 0xF0000000
+#define CONFIG_SYS_SDRAM_BASE 0x00000000
+#if !defined(CONFIG_SYS_LOWBOOT)
+#define CONFIG_SYS_DEFAULT_MBAR 0x80000000
+#else
+#define CONFIG_SYS_DEFAULT_MBAR 0xF0000000
+#endif
+
+/*
+ * Use SRAM until RAM will be available
+ */
+#define CONFIG_SYS_INIT_RAM_ADDR MPC5XXX_SRAM
+#define CONFIG_SYS_INIT_RAM_END MPC5XXX_SRAM_SIZE
+
+#define CONFIG_SYS_GBL_DATA_SIZE 4096
+#define CONFIG_SYS_GBL_DATA_OFFSET \
+ (CONFIG_SYS_INIT_RAM_END - CONFIG_SYS_GBL_DATA_SIZE)
+#define CONFIG_SYS_INIT_SP_OFFSET CONFIG_SYS_GBL_DATA_OFFSET
+
+#define CONFIG_SYS_MONITOR_BASE TEXT_BASE
+#if (CONFIG_SYS_MONITOR_BASE < CONFIG_SYS_FLASH_BASE)
+#define CONFIG_SYS_RAMBOOT 1
+#endif
+
+#define CONFIG_SYS_MONITOR_LEN (256 << 10)
+#define CONFIG_SYS_MALLOC_LEN (4096 << 10)
+#define CONFIG_SYS_BOOTMAPSZ (8 << 20)
+
+/*
+ * Ethernet configuration
+ */
+#define CONFIG_MPC5xxx_FEC 1
+#define CONFIG_MPC5xxx_FEC_MII100
+#define CONFIG_PHY_ADDR 0x00
+#define CONFIG_PHY_RESET_DELAY 1000
+
+#define CONFIG_NETCONSOLE /* include NetConsole support */
+
+/*
+ * GPIO configuration
+ */
+#define CONFIG_SYS_GPS_PORT_CONFIG 0xA2552112
+
+/*
+ * Miscellaneous configurable options
+ */
+#define CONFIG_SYS_LONGHELP
+#define CONFIG_AUTO_COMPLETE 1
+#define CONFIG_SYS_PROMPT "=> "
+#define CONFIG_SYS_HUSH_PARSER
+#define CONFIG_SYS_PROMPT_HUSH_PS2 "> "
+
+#define CONFIG_AUTOBOOT_KEYED
+#define CONFIG_AUTOBOOT_PROMPT "autoboot in %d seconds\n"
+#define CONFIG_AUTOBOOT_DELAY_STR " "
+
+#define CONFIG_LOOPW 1
+#define CONFIG_MX_CYCLIC 1
+#define CONFIG_ZERO_BOOTDELAY_CHECK
+
+#define CONFIG_SYS_CBSIZE 1024
+#define CONFIG_SYS_PBSIZE (CONFIG_SYS_CBSIZE+sizeof(CONFIG_SYS_PROMPT)+16)
+#define CONFIG_SYS_MAXARGS 32
+#define CONFIG_SYS_BARGSIZE CONFIG_SYS_CBSIZE
+
+#define CONFIG_SYS_ALT_MEMTEST
+#define CONFIG_SYS_MEMTEST_SCRATCH 0x00001000
+#define CONFIG_SYS_MEMTEST_START 0x00010000
+#define CONFIG_SYS_MEMTEST_END 0x019fffff
+
+#define CONFIG_SYS_LOAD_ADDR 0x00100000
+
+#define CONFIG_SYS_HZ 1000
+
+#define CONFIG_LAST_STAGE_INIT
+
+/*
+ * Various low-level settings
+ */
+#define CONFIG_SYS_SDRAM_CS1 1
+#define CONFIG_SYS_XLB_PIPELINING 1
+
+#define CONFIG_SYS_HID0_INIT HID0_ICE | HID0_ICFI
+#define CONFIG_SYS_HID0_FINAL HID0_ICE
+
+#if defined(CONFIG_SYS_LOWBOOT)
+#define CONFIG_SYS_BOOTCS_START CONFIG_SYS_FLASH_BASE
+#define CONFIG_SYS_BOOTCS_SIZE CONFIG_SYS_FLASH_SIZE
+#define CONFIG_SYS_BOOTCS_CFG 0x0002DD00
+#endif
+
+#define CONFIG_SYS_CS4_START 0x60000000
+#define CONFIG_SYS_CS4_SIZE 0x1000
+#define CONFIG_SYS_CS4_CFG 0x0008FC00
+
+#define CONFIG_SYS_CS0_START CONFIG_SYS_FLASH_BASE
+#define CONFIG_SYS_CS0_SIZE CONFIG_SYS_FLASH_SIZE
+#define CONFIG_SYS_CS0_CFG 0x0002DD00
+
+#define CONFIG_SYS_CS_BURST 0x00000000
+#define CONFIG_SYS_CS_DEADCYCLE 0x11111111
+
+#if !defined(CONFIG_SYS_LOWBOOT)
+#define CONFIG_SYS_RESET_ADDRESS 0xfff00100
+#else
+#define CONFIG_SYS_RESET_ADDRESS 0xff000100
+#endif
+
+/*
+ * USB
+ */
+#define CONFIG_USB_OHCI_NEW
+#define CONFIG_SYS_OHCI_BE_CONTROLLER
+#define CONFIG_USB_STORAGE
+
+#define CONFIG_USB_CLOCK 0x00013333
+#define CONFIG_USB_CONFIG 0x00002000
+
+#define CONFIG_SYS_USB_OHCI_MAX_ROOT_PORTS 15
+#define CONFIG_SYS_USB_OHCI_REGS_BASE MPC5XXX_USB
+#define CONFIG_SYS_USB_OHCI_SLOT_NAME "mpc5200"
+#define CONFIG_SYS_USB_OHCI_CPU_INIT
+
+/*
+ * IDE/ATA
+ */
+#define CONFIG_IDE_RESET
+#define CONFIG_IDE_PREINIT
+
+#define CONFIG_SYS_IDE_MAXBUS 1
+#define CONFIG_SYS_IDE_MAXDEVICE 1
+
+#define CONFIG_SYS_ATA_IDE0_OFFSET 0x0000
+#define CONFIG_SYS_ATA_BASE_ADDR MPC5XXX_ATA
+#define CONFIG_SYS_ATA_DATA_OFFSET (0x0060)
+#define CONFIG_SYS_ATA_REG_OFFSET (CONFIG_SYS_ATA_DATA_OFFSET)
+#define CONFIG_SYS_ATA_ALT_OFFSET (0x005C)
+#define CONFIG_SYS_ATA_STRIDE 4
+
+#define CONFIG_ATAPI 1
+#define CONFIG_LBA48 1
+
+#endif /* __CONFIG_H */
+
--
1.6.0.6
2
7

11 Mar '09
OMAP3 support recently merged is version from mid december 2008.
This patch series adds some additional clean up, fixes and
improvements done since then. It brings U-Boot mainline in sync
with U-Boot tree of OMAP3 developers ("omap3-dev").
Changes in v2:
- Rebase against commit 6b67962fd69ac0bcdf1a982669a029c2f0a7bcc1
"Merge branch 'master' of git://git.denx.de/u-boot-ppc4xx"
u-boot.git main branch
- Update git commit message in Pandora pin mux patch
- Re-name 'serial' to 'serial#'
- In serial number patch, don't copy from a memory to an other,
instead just update the pointer
- Make beagle_revision_c static local variable and add function to
return the value.
This v2 patch series makes all older patches of this series
obsolete.
Best regards
Dirk
5
28
Hi,
I have several PCI-E related problems on Kilauea board Rev 1.2
1. With u-boot v2009.01 and latest git I'm getting machine check
exception when PCI-E card is plugged into slot 0. There's no
problem if the same card is plugged into slot 1.
This seems to be a regression introduced after
2008.10-rc2-02699-g725c8dd
(version shipped on AMCC resource CD), as with this version both slots
function properly.
Any hints what could be the problem with latest u-boots ?
U-Boot 2009.01-00336-g952a6bd (Feb 16 2009 - 16:29:56)
CPU: AMCC PowerPC 405EX Rev. C at 600 MHz (PLB=200, OPB=100, EBC=100 MHz)
Security support
Bootstrap Option H - Boot ROM Location I2C (Addr 0x52)
16 kB I-Cache 16 kB D-Cache
Board: Kilauea - AMCC PPC405EX Evaluation Board
I2C: ready
DTT1: 31 C
DRAM: 256 MB
FLASH: 64 MB
NAND: 64 MiB
PCI: Bus Dev VenId DevId Class Int
PCIE0: successfully set as root-complex
Machine Check Exception.
Caused by (from msr): regs 0fe9fc78 Data PLB Error
NIP: 00000000 XER: 00000000 LR: 0FFD8794 REGS: 0fe9fc78 TRAP: 0200 DEAR:
00000000
MSR: 00000000 EE: 0 PR: 0 FP: 0 ME: 0 IR/DR: 00
GPR00: 00000000 0FE9FD68 0FE9FF44 B0000000 00000000 0FE9FD58 00000003
00100004
GPR08: 00000000 A0000000 0FE9FD58 0000003A 07FFFFFC 7FF67EFF 0FFF1500
10004000
GPR16: 74FEFFE7 0FFE000C 0FE9FE28 0FE9FE2A 0FE9FDB0 0FE9FDB4 0FE9FDBC
0FFF0CC0
GPR24: 00000000 00000018 00000004 00000003 00100004 0FFF0CA8 0FFF1C10
00000004
Call backtrace:
0FFF0CA8 0FFD86F8 0FFB4B28 0FFB6058 0FFB6118 0FFB5330 0FFB5404
0FFD2558 0FFD84A0 0FFB51C4 0FFA7F10 0FFA66A4
machine check
2. Another problem is that in bootstrap configuration B (CPU - 333 Mhz,
PLB 166MHz)
PCI-E cards are not recognized in any slot. This happens with all
u-boot versions I've
tested. Linux also does not recognize PCI-E cards. Kilauea board
manual says that PCI
clock is determined by CPLD. Could it be CPLD/FPGA bug ?
Thanks.
Felix.
2
12
Hi folks,
I have an ADSL router (Linksys WAG200G) that is based on the TI AR7
(MIPS) architecture.
Unfortunately, it has been supplied with a boot loader (ADAM2) that has
been configured to not allow interruption, or upload of replacement
firmwares via the bootloader. While I'd love to be able to hack on the
firmware for this router, I am understandably reluctant to brick it.
I have constructed a JTAG cable, and am in the process of ensuring that
it is working correctly. Once I have done that, I'd like to replace the
bootloader with one that DOES allow network access, and upload of
replacement payloads, without requiring a lengthy JTAG session every time.
I realise that it probably makes more sense to try to rebuild an ADAM2
loader with the required options enabled, but would prefer to use an
(supported) open source project if possible.
So, does Das U-Boot support the AR7 family of chips? The CPU is labeled
TNETD7300GDU (52A29HW), if that helps.
Thanks,
Rogan
P.S. Please Cc me, I am not subscribed to this list.
1
1
Dear Kim, Andy & Jon,
I have the following patches still marked as open in my list. Could
you please have a look...
8xxx:
11/06 Anton Vorontsov [U-Boot] [PATCH] mpc83xx: increase BOOTMAPSZ to 16MB
12/11 Paul Gortmaker [U-Boot] [PATCH] tsec: report when there is no vendor specific PHY support.
12/30 Poonam_Aggrwal-b1 [U-Boot] [PATCH][u-boot-85xx]The 32bit errata fix for 8572 for DDR2 (fwd)
01/15 hamoshame Lamotek [U-Boot] MPC8572DS Registered DDR2 support.
01/22 Pieter [U-Boot] Custom MPC8548 boot using FDT problem
01/22 Scott Wood Re: [U-Boot] mpc8313erdb: crash in image_print_type()
02/04 Jon Loeliger Re: [U-Boot] [PATCH 4/8] mpc86xx: Add support to populate addr map based on BATs
02/04 Jon Loeliger Re: [U-Boot] [PATCH 8/8] mpc8641hpcn: Change PCI MEM pci bus address
02/04 Jon Loeliger Re: [U-Boot] [PATCH 1/8] mpc8641hpcn: Set up outbound pci windows before inbound
02/04 Jon Loeliger Re: [U-Boot] [PATCH 5/8] mpc8641hpcn: Clean up PCI mapping concepts
02/05 Valeriy Glushkov [U-Boot] [PATCH] mpc8349itx: allow SATA boot from the onboard SIL1334
02/10 "Ajeesh Kumar" U-boot level MPC8548 Ethernet internal/External Loop back testing
02/12 Becky Bruce [U-Boot] [PATCH] mpc8641hpcn: Indicate 36-bit addr map in boot messages
02/12 Becky Bruce [U-Boot] [PATCH] MPC86xx: set CONFIG_MAX_MEM_MAPPED to 2G by default
02/12 Becky Bruce Re: [U-Boot] [PATCH] MPC86xx: set CONFIG_MAX_MEM_MAPPED to 2G by default
02/12 Jon Loeliger Re: [U-Boot] [PATCH] MPC86xx: set CONFIG_MAX_MEM_MAPPED to 2G by default
02/16 Kim Phillips Re: [U-Boot] [PATCH] mpc8349itx: allow SATA boot from the onboard SIL1334
02/17 Heiko Schocher [U-Boot] [PATCH 03/12 v2] 83xx, kmeter1: add I2C, dtt, eeprom support
02/17 Heiko Schocher [U-Boot] [PATCH 08/12 v2] 83xx, kmeter: QE_ENET10 errata for Silicon Revision 2.1
02/17 Heiko Schocher [U-Boot] [PATCH 09/12 v2] 8360, kmeter1: added bootcount feature.
02/17 Kumar Gala [U-Boot] [PATCH] fsl: Don't spew messages related to PHY fixup of device tree
02/19 Anton Vorontsov [U-Boot] [PATCH 0/7] Some PCIe patches for MPC83xx
02/19 Anton Vorontsov [U-Boot] [PATCH 1/7] mpc83xx: MPC837XEMDS: Initialize SerDes before negating PCIE reset signal
02/19 Anton Vorontsov [U-Boot] [PATCH 2/7] PCI: Add pci_last_busno() helper
02/19 Anton Vorontsov [U-Boot] [PATCH 3/7] mpc83xx: PCIe: Don't start bus enumeration at 0
02/19 Anton Vorontsov [U-Boot] [PATCH 4/7] mpc83xx: PCIe: Fix CONFIG_PCI_SCAN_SHOW reporting bogus values
02/19 Anton Vorontsov [U-Boot] [PATCH 5/7] mpc83xx: PCI: Fix bus-range fdt fixups for PCI1 controllers
02/19 Anton Vorontsov [U-Boot] [PATCH 6/7] mpc83xx: PCI: Fix hard-coded first_busno value
02/19 Anton Vorontsov [U-Boot] [PATCH 7/7] mpc83xx: MPC837XERDB: Add PCIe support
02/19 Heiko Schocher [U-Boot] [PATCH 3/9 v3] 83xx, kmeter1: add I2C, dtt, eeprom support
02/19 Heiko Schocher [U-Boot] [PATCH 5/9 v3] 83xx, kmeter1: autodetect size of DDR II RAM
02/19 Heiko Schocher [U-Boot] [PATCH 4/9 v3] 83xx, i2c: add mux support for fsl_i2c
02/19 Heiko Schocher [U-Boot] [PATCH 6/9 v3] 83xx: add missing TIMING_CFG1_CASLAT_* defines
02/19 Heiko Schocher [U-Boot] [PATCH 7/9 v3] 83xx, kmeter1: updates for 2009.03
02/19 Heiko Schocher [U-Boot] [PATCH 8/9 v3] 83xx, kmeter: QE_ENET10 errata for Silicon Revision 2.1
02/19 Heiko Schocher [U-Boot] [PATCH 9/9 v3] 8360, kmeter1: added bootcount feature.
Thanks in advance.
Best regards,
Wolfgang Denk
--
DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd(a)denx.de
Anything free is worth what you pay for it.
8
9
Stefan et al,
I am trying to troubleshoot a weird PCIe problem on a PPC460GT based
target, and it is getting curiouser and curiouser.
There is a tlb overlap I mentioned in an earlier email; on top of that
there are some things happening in cpu/ppc4xx/4xx_pcie.c which I also
find hard to understand:
there is a static function pcie_get_base(), which returns a value as in
address = pcie_get_base(hose, devfn)
there are two instances of this, in both cases `address' is never used.
The CONFIG_SYS_PCIE0_XCFGBASE constant (and its counterparts for other
PCIe ports) is defined and used in the code, and gets a TLB entry
assigned, but I can't find a place where it is programmed into the CPU
- how does it know where this section is?!
I have several different targets with different PCIe components, but
all using the same base CPU subsystem design, and on some of them PCIe
components misbehave, namely, PCIe memory read transactions fail with
a machine check after a timeout, even though the PCIe side of things
is fine (when looking with a protocol analyzer).
Any insight/explanations/suggestions would be highly appreciated,
TIA,
vadim
3
6
1. RD_TO_PRE missed to add the AL, and need min 2 clocks for
tRTP according to DDR2 JEDEC spec.
2. WRTORD - tWTR need min 2 clocks according to DDR2 JEDEC spec.
3. add the support of DDR2-533,667,800 DIMMs
4. cpo
5. make the AL to min to gain better performance.
The Micron MT9HTF6472CHY-667D1 DIMMs test passed on
MPC837xEMDS platform at 266MHz/333MHz/400MHz data rate.
Reported-by: Joakim Tjernlund <Joakim.Tjernlund(a)transmode.se>
Signed-off-by: Dave Liu <daveliu(a)freescale.com>
---
cpu/mpc83xx/spd_sdram.c | 26 +++++++++++++++++++++++---
1 files changed, 23 insertions(+), 3 deletions(-)
diff --git a/cpu/mpc83xx/spd_sdram.c b/cpu/mpc83xx/spd_sdram.c
index 42a4e67..ff15cda 100644
--- a/cpu/mpc83xx/spd_sdram.c
+++ b/cpu/mpc83xx/spd_sdram.c
@@ -319,7 +319,20 @@ long int spd_sdram()
ddrc_clk = gd->mem_clk / 1000000;
effective_data_rate = 0;
- if (max_data_rate >= 390 && max_data_rate < 460) { /* it is DDR 400 */
+ if (max_data_rate >= 460) { /* it is DDR2-800, 667, 533 */
+ if (spd.cas_lat & 0x08)
+ caslat = 3;
+ else
+ caslat = 4;
+ if (ddrc_clk <= 460 && ddrc_clk > 350)
+ effective_data_rate = 400;
+ else if (ddrc_clk <=350 && ddrc_clk > 280)
+ effective_data_rate = 333;
+ else if (ddrc_clk <= 280 && ddrc_clk > 230)
+ effective_data_rate = 266;
+ else
+ effective_data_rate = 200;
+ } else if (max_data_rate >= 390 && max_data_rate < 460) { /* it is DDR 400 */
if (ddrc_clk <= 460 && ddrc_clk > 350) {
/* DDR controller clk at 350~460 */
effective_data_rate = 400; /* 5ns */
@@ -466,6 +479,8 @@ long int spd_sdram()
} else {
twr_clk = picos_to_clk(spd.twr * 250);
twtr_clk = picos_to_clk(spd.twtr * 250);
+ if (twtr_clk < 2)
+ twtr_clk = 2;
}
/*
@@ -529,7 +544,7 @@ long int spd_sdram()
if (spd.mem_type == SPD_MEMTYPE_DDR2
&& (odt_wr_cfg || odt_rd_cfg)
&& (caslat < 4)) {
- add_lat = trcd_clk - 1;
+ add_lat = 4 - caslat;
if ((add_lat + caslat) < 4) {
add_lat = 0;
}
@@ -566,6 +581,9 @@ long int spd_sdram()
/* Convert SPD value from quarter nanos to picos. */
trtp_clk = picos_to_clk(spd.trtp * 250);
+ if (trtp_clk < 2)
+ trtp_clk = 2;
+ trtp_clk += add_lat;
cke_min_clk = 3; /* By the book. */
four_act = picos_to_clk(37500); /* By the book. 1k pages? */
@@ -579,7 +597,9 @@ long int spd_sdram()
if (spd.mem_type == SPD_MEMTYPE_DDR2) {
if (effective_data_rate == 266) {
cpo = 0x4; /* READ_LAT + 1/2 */
- } else if (effective_data_rate == 333 || effective_data_rate == 400) {
+ } else if (effective_data_rate == 333) {
+ cpo = 0x6; /* READ_LAT + 1 */
+ } else if (effective_data_rate == 400) {
cpo = 0x7; /* READ_LAT + 5/4 */
} else {
/* Automatic calibration */
--
1.5.4
4
8

09 Mar '09
This adds tsec12ioovcr to include/asm-ppc/immap_85xx.h (was reserved.)
Signed-off-by: Sergey Kubushyn <ksi(a)koi8.net>
---
diff -purN u-boot.orig/include/asm-ppc/immap_85xx.h u-boot/include/asm-ppc/immap_85xx.h
--- u-boot.orig/include/asm-ppc/immap_85xx.h 2009-02-19 13:39:31.000000000 -0800
+++ u-boot/include/asm-ppc/immap_85xx.h 2009-02-23 10:49:09.000000000 -0800
@@ -1667,7 +1667,7 @@ typedef struct ccsr_gur {
uint lbiuiplldcr0; /* 0xe0f1c -- LBIU PLL Debug Reg 0 */
uint lbiuiplldcr1; /* 0xe0f20 -- LBIU PLL Debug Reg 1 */
uint ddrioovcr; /* 0xe0f24 - DDR IO Override Control */
- uint res14; /* 0xe0f28 */
+ uint tsec12ioovcr; /* 0xe0f28 - eTSEC 1/2 IO override control */
uint tsec34ioovcr; /* 0xe0f2c - eTSEC 3/4 IO override control */
char res15[61648]; /* 0xe0f30 to 0xefffff */
} ccsr_gur_t;
2
1