* [RFC PATCH] [MTD] [OneNAND] Cache Read support
@ 2007-08-01 0:20 Kyungmin Park
2007-08-01 6:24 ` Adrian Hunter
0 siblings, 1 reply; 4+ messages in thread
From: Kyungmin Park @ 2007-08-01 0:20 UTC (permalink / raw)
To: linux-mtd
Hi,
This patch supports the Cache Read feature in OneNAND.
It's similar with read-while-loading except while read it does sensing the page buffer in NAND core.
So it's called Transfer-While-Sensing. you can find it in OneNAND Spec. in detail.
Now there's no big performance gain in our test board, Apollon(OMAP2). But others are maybe different.
Any comments are welcome.
Thank you,
Kyungmin Park
-
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c
index 7d194cf..dfc16c0 100644
--- a/drivers/mtd/onenand/onenand_base.c
+++ b/drivers/mtd/onenand/onenand_base.c
@@ -124,6 +124,28 @@ static int onenand_bufferram_address(struct onenand_chip *this, int block)
}
/**
+ * onenand_copyback_page_address - [DEFAULT] Get copyback page address
+ * @param page the page address
+ * @param sector the sector address
+ * @return combined page and sector address
+ *
+ * Setup Start Address 4 Register (F103h)
+ */
+static int onenand_copyback_page_address(int page, int sector)
+{
+ /*
+ * Flash Copy Back Page Address, Flash Copy Back Sector Address
+ * First Page Address, First Sector Address of Cache Read
+ */
+ int fcpa, fcsa;
+
+ fcpa = page & ONENAND_FCPA_MASK;
+ fcsa = sector & ONENAND_FCSA_MASK;
+
+ return ((fcpa << ONENAND_FCPA_SHIFT) | fcsa);
+}
+
+/**
* onenand_page_address - [DEFAULT] Get page address
* @param page the page address
* @param sector the sector address
@@ -184,6 +206,9 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le
struct onenand_chip *this = mtd->priv;
int value, readcmd = 0, block_cmd = 0;
int block, page;
+ /* Now we use page size operation */
+ int sectors = 4, count = 4;
+ int dataram = -1;
/* Address translation */
switch (cmd) {
@@ -191,6 +216,8 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le
case ONENAND_CMD_LOCK:
case ONENAND_CMD_LOCK_TIGHT:
case ONENAND_CMD_UNLOCK_ALL:
+ case ONENAND_CMD_CACHE_READ:
+ case ONENAND_CMD_FINISH_CACHE_READ:
block = -1;
page = -1;
break;
@@ -235,6 +262,33 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le
return 0;
}
+ if (cmd == ONENAND_CMD_CACHE_READ_FCBA) {
+ /* Write 'FCBA' of Flash */
+ this->write_word(block, this->base + ONENAND_REG_START_ADDRESS3);
+ /* Write 'FCPA, FCSA' of Flash */
+ value = onenand_copyback_page_address(page, sectors);
+ this->write_word(value, this->base + ONENAND_REG_START_ADDRESS4);
+ /* Write 'BSA, BSC' of Flash */
+ dataram = ONENAND_SET_NEXT_BUFFERRAM(this);
+ value = onenand_buffer_address(dataram, sectors, count);
+ this->write_word(value, this->base + ONENAND_REG_START_BUFFER);
+
+ return 0;
+ }
+
+ if (cmd == ONENAND_CMD_CACHE_READ_FBA) {
+ /* Write 'DFS, FBA' of Flash */
+ value = onenand_block_address(this, block);
+ this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1);
+ /* Select DataRAM for DDP */
+ value = onenand_bufferram_address(this, block);
+ this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2);
+ /* Write 'FPA, FSA' of Flash */
+ value = onenand_page_address(page, sectors);
+ this->write_word(value, this->base + ONENAND_REG_START_ADDRESS8);
+ return 0;
+ }
+
if (block != -1) {
/* Write 'DFS, FBA' of Flash */
value = onenand_block_address(this, block);
@@ -248,9 +302,6 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le
}
if (page != -1) {
- /* Now we use page size operation */
- int sectors = 4, count = 4;
- int dataram;
switch (cmd) {
case ONENAND_CMD_READ:
@@ -270,9 +321,11 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le
value = onenand_page_address(page, sectors);
this->write_word(value, this->base + ONENAND_REG_START_ADDRESS8);
- /* Write 'BSA, BSC' of DataRAM */
- value = onenand_buffer_address(dataram, sectors, count);
- this->write_word(value, this->base + ONENAND_REG_START_BUFFER);
+ if (dataram >= 0) {
+ /* Write 'BSA, BSC' of DataRAM */
+ value = onenand_buffer_address(dataram, sectors, count);
+ this->write_word(value, this->base + ONENAND_REG_START_BUFFER);
+ }
if (readcmd) {
/* Select DataRAM for DDP */
@@ -763,6 +816,139 @@ static void onenand_release_device(struct mtd_info *mtd)
}
/**
+ * onenand_cache_read - [MTD Interface] Read data from flash
+ * @param mtd MTD device structure
+ * @param from offset to read from
+ * @param len number of bytes to read
+ * @param retlen pointer to variable to store the number of read bytes
+ * @param buf the databuffer to put data
+ *
+ * Read with ecc using cache read command
+*/
+static int onenand_cache_read(struct mtd_info *mtd, loff_t from, size_t len,
+ size_t *retlen, u_char *buf)
+{
+ struct onenand_chip *this = mtd->priv;
+ struct mtd_ecc_stats stats;
+ int read = 0, column = 0;
+ int thislen;
+ int ret = 0, status;
+ int writesize = this->writesize;
+
+ DEBUG(MTD_DEBUG_LEVEL3, "onenand_cache_read: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len);
+
+ /* Grab the lock and see if the device is available */
+ onenand_get_device(mtd, FL_READING);
+
+ stats = mtd->ecc_stats;
+
+ /* Transfer-While-Sensing method */
+
+ thislen = min_t(int, writesize, len - read);
+ column = from & (writesize - 1);
+ if (column + thislen > writesize)
+ thislen = writesize - column;
+
+ /* Setup first page */
+ this->command(mtd, ONENAND_CMD_CACHE_READ_FCBA, from, thislen);
+
+ /*
+ * Switch the bufferRAM to point the correct one
+ * It will be switched the bufferRAM at 'n-1'th page read (see below)
+ */
+ ONENAND_SET_NEXT_BUFFERRAM(this);
+
+ /* Setup second page */
+ this->command(mtd, ONENAND_CMD_CACHE_READ_FBA, from + thislen, writesize);
+
+ /* Issue the first read page */
+ this->command(mtd, ONENAND_CMD_CACHE_READ, from, thislen);
+
+ /* Check the Controller Status */
+ while (1) {
+ status = this->read_word(this->base + ONENAND_REG_CTRL_STATUS);
+
+ if ((status & ONENAND_CTRL_ONGO) &&
+ (status & ONENAND_CTRL_LOAD))
+ break;
+ }
+
+ while (!ret) {
+ /* Is there more pages? */
+ if (read + thislen + writesize >= len)
+ break;
+
+ /* Setup the 'n-2'th page */
+ this->command(mtd, ONENAND_CMD_CACHE_READ_FBA, from + thislen + writesize, writesize);
+
+ /* Update the 'n-3'th page bufferram */
+ ONENAND_SET_NEXT_BUFFERRAM(this);
+
+ /* Wait the 'n-3'th page */
+ ret = this->wait(mtd, FL_READING);
+ onenand_update_bufferram(mtd, from, !ret);
+
+ /* Update the 'n-2'th page address */
+ from += thislen;
+
+ /* Issues the 'n-2'th page */
+ this->command(mtd, ONENAND_CMD_CACHE_READ, from, writesize);
+
+ /* Read the 'n-3'th page */
+ this->read_bufferram(mtd, ONENAND_DATARAM, buf, column, thislen);
+ read += thislen;
+ buf += thislen;
+
+ thislen = min_t(int, writesize, len - read);
+ column = 0;
+ }
+
+ /* Update the 'n-1'th page bufferram */
+ ONENAND_SET_NEXT_BUFFERRAM(this);
+
+ /* Wait the 'n-1'th page */
+ ret = this->wait(mtd, FL_READING);
+ onenand_update_bufferram(mtd, from, !ret);
+
+ /* Update the 'n'th page address */
+ from += thislen;
+
+ /* Issue the 'n'th page read command */
+ this->command(mtd, ONENAND_CMD_FINISH_CACHE_READ, from, writesize);
+
+ /* Read the 'n-1'th page */
+ this->read_bufferram(mtd, ONENAND_DATARAM, buf, column, thislen);
+ read += thislen;
+ buf += thislen;
+
+ /* Update the 'n'th page bufferram */
+ ONENAND_SET_NEXT_BUFFERRAM(this);
+ thislen = min_t(int, writesize, len - read);
+ column = 0;
+
+ /* Wait the 'n'th page */
+ ret = this->wait(mtd, FL_READING);
+ onenand_update_bufferram(mtd, from, !ret);
+
+ /* Read the 'n'th page */
+ this->read_bufferram(mtd, ONENAND_DATARAM, buf, column, thislen);
+ read += thislen;
+
+ /* Deselect and wake up anyone waiting on the device */
+ onenand_release_device(mtd);
+
+ *retlen = read;
+
+ if (mtd->ecc_stats.failed - stats.failed)
+ return -EBADMSG;
+
+ if (ret)
+ return ret;
+
+ return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0;
+}
+
+/**
* onenand_read - [MTD Interface] Read data from flash
* @param mtd MTD device structure
* @param from offset to read from
@@ -791,6 +977,13 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
return -EINVAL;
}
+ /*
+ * If the requested reads are more than 2 pages and can cache read,
+ * we use the cache read command
+ */
+ if (len >= (this->writesize << 1) && ONENAND_CAN_CACHE_READ(this))
+ return onenand_cache_read(mtd, from, len, retlen, buf);
+
/* Grab the lock and see if the device is available */
onenand_get_device(mtd, FL_READING);
@@ -2163,6 +2356,7 @@ static int onenand_lock_user_prot_reg(struct mtd_info *mtd, loff_t from,
* Check and set OneNAND features
* - lock scheme
* - two plane
+ * - cache read
*/
static void onenand_check_features(struct mtd_info *mtd)
{
@@ -2183,11 +2377,14 @@ static void onenand_check_features(struct mtd_info *mtd)
if (!ONENAND_IS_DDP(this))
this->options |= ONENAND_HAS_2PLANE;
this->options |= ONENAND_HAS_UNLOCK_ALL;
+ this->options |= ONENAND_HAS_CACHE_READ;
case ONENAND_DEVICE_DENSITY_1Gb:
- /* A-Die has all block unlock */
- if (process)
+ /* A-Die or later */
+ if (process) {
this->options |= ONENAND_HAS_UNLOCK_ALL;
+ this->options |= ONENAND_HAS_CACHE_READ;
+ }
break;
default:
@@ -2200,9 +2397,11 @@ static void onenand_check_features(struct mtd_info *mtd)
if (this->options & ONENAND_HAS_CONT_LOCK)
printk(KERN_DEBUG "Lock scheme is Continuous Lock\n");
if (this->options & ONENAND_HAS_UNLOCK_ALL)
- printk(KERN_DEBUG "Chip support all block unlock\n");
+ printk(KERN_DEBUG "Chip supports all block unlock\n");
if (this->options & ONENAND_HAS_2PLANE)
- printk(KERN_DEBUG "Chip has 2 plane\n");
+ printk(KERN_DEBUG "Chip has 2 planes\n");
+ if (this->options & ONENAND_HAS_CACHE_READ)
+ printk(KERN_DEBUG "Chip supports the cache read\n");
}
/**
diff --git a/include/linux/mtd/onenand.h b/include/linux/mtd/onenand.h
index fd0a260..6f952dd 100644
--- a/include/linux/mtd/onenand.h
+++ b/include/linux/mtd/onenand.h
@@ -160,6 +160,9 @@ struct onenand_chip {
#define ONENAND_IS_2PLANE(this) (0)
#endif
+#define ONENAND_CAN_CACHE_READ(this) \
+ (this->options & ONENAND_HAS_CACHE_READ)
+
/* Check byte access in OneNAND */
#define ONENAND_CHECK_BYTE_ACCESS(addr) (addr & 0x1)
@@ -169,6 +172,7 @@ struct onenand_chip {
#define ONENAND_HAS_CONT_LOCK (0x0001)
#define ONENAND_HAS_UNLOCK_ALL (0x0002)
#define ONENAND_HAS_2PLANE (0x0004)
+#define ONENAND_HAS_CACHE_READ (0x0008)
#define ONENAND_PAGEBUF_ALLOC (0x1000)
#define ONENAND_OOBBUF_ALLOC (0x2000)
diff --git a/include/linux/mtd/onenand_regs.h b/include/linux/mtd/onenand_regs.h
index c46161f..a5f20f6 100644
--- a/include/linux/mtd/onenand_regs.h
+++ b/include/linux/mtd/onenand_regs.h
@@ -90,6 +90,13 @@
#define ONENAND_DDP_CHIP1 (1 << ONENAND_DDP_SHIFT)
/*
+ * Start Address 4 F103h (R/W)
+ */
+#define ONENAND_FCPA_MASK (0x3f)
+#define ONENAND_FCPA_SHIFT (2)
+#define ONENAND_FCSA_MASK (0x03)
+
+/*
* Start Address 8 F107h (R/W)
*/
#define ONENAND_FPA_MASK (0x3f)
@@ -119,6 +126,8 @@
#define ONENAND_CMD_LOCK (0x2A)
#define ONENAND_CMD_LOCK_TIGHT (0x2C)
#define ONENAND_CMD_UNLOCK_ALL (0x27)
+#define ONENAND_CMD_CACHE_READ (0x0E)
+#define ONENAND_CMD_FINISH_CACHE_READ (0x0C)
#define ONENAND_CMD_ERASE (0x94)
#define ONENAND_CMD_RESET (0xF0)
#define ONENAND_CMD_OTP_ACCESS (0x65)
@@ -126,6 +135,8 @@
/* NOTE: Those are not *REAL* commands */
#define ONENAND_CMD_BUFFERRAM (0x1978)
+#define ONENAND_CMD_CACHE_READ_FCBA (0xFCBA)
+#define ONENAND_CMD_CACHE_READ_FBA (0xFBA)
/*
* System Configuration 1 Register F221h (R, R/W)
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [RFC PATCH] [MTD] [OneNAND] Cache Read support
2007-08-01 0:20 [RFC PATCH] [MTD] [OneNAND] Cache Read support Kyungmin Park
@ 2007-08-01 6:24 ` Adrian Hunter
2007-08-01 7:09 ` Kyungmin Park
0 siblings, 1 reply; 4+ messages in thread
From: Adrian Hunter @ 2007-08-01 6:24 UTC (permalink / raw)
To: kmpark; +Cc: linux-mtd
ext Kyungmin Park wrote:
> This patch supports the Cache Read feature in OneNAND.
> It's similar with read-while-loading except while read it does sensing the page buffer in NAND core.
> So it's called Transfer-While-Sensing. you can find it in OneNAND Spec. in detail.
>
> Now there's no big performance gain in our test board, Apollon(OMAP2). But others are maybe different.
>
> Any comments are welcome.
Cool!
Presume you have run the NAND tests
^ permalink raw reply [flat|nested] 4+ messages in thread
* RE: [RFC PATCH] [MTD] [OneNAND] Cache Read support
2007-08-01 6:24 ` Adrian Hunter
@ 2007-08-01 7:09 ` Kyungmin Park
2007-08-01 8:52 ` Adrian Hunter
0 siblings, 1 reply; 4+ messages in thread
From: Kyungmin Park @ 2007-08-01 7:09 UTC (permalink / raw)
To: 'Adrian Hunter'; +Cc: linux-mtd
> ext Kyungmin Park wrote:
> > This patch supports the Cache Read feature in OneNAND.
> > It's similar with read-while-loading except while read it does sensing the page buffer in NAND
> core.
> > So it's called Transfer-While-Sensing. you can find it in OneNAND Spec. in detail.
> >
> > Now there's no big performance gain in our test board, Apollon(OMAP2). But others are maybe
> different.
> >
> > Any comments are welcome.
>
> Cool!
>
> Presume you have run the NAND tests
Sure, it passed NAND tests.
Could you review the code?
I wonder why there's no performance gain. It's faster than read-while-loading in the Spec.
Software overhead? Or there's not many 2 or more pages read?
Thank you,
Kyungmin Park
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [RFC PATCH] [MTD] [OneNAND] Cache Read support
2007-08-01 7:09 ` Kyungmin Park
@ 2007-08-01 8:52 ` Adrian Hunter
0 siblings, 0 replies; 4+ messages in thread
From: Adrian Hunter @ 2007-08-01 8:52 UTC (permalink / raw)
To: kmpark; +Cc: linux-mtd
ext Kyungmin Park wrote:
>
>> ext Kyungmin Park wrote:
>>> This patch supports the Cache Read feature in OneNAND.
>>> It's similar with read-while-loading except while read it does sensing the page buffer in NAND
>> core.
>>> So it's called Transfer-While-Sensing. you can find it in OneNAND Spec. in detail.
>>>
>>> Now there's no big performance gain in our test board, Apollon(OMAP2). But others are maybe
>> different.
>>> Any comments are welcome.
>> Cool!
>>
>> Presume you have run the NAND tests
>
> Sure, it passed NAND tests.
>
> Could you review the code?
I will try to find some time to look at it maybe this week.
> I wonder why there's no performance gain. It's faster than read-while-loading in the Spec.
> Software overhead? Or there's not many 2 or more pages read?
How are you measuring performance? I would suggest either dd (if you don't have bad blocks)
or write your own program.
As I see it, unless the read from dataRAM is faster than the sensing/transfer, there won't be
a performance improvement. So the faster the OneNAND frequency the better. Ditto bus and
CPU frequencies probably (for memcpy).
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2007-08-01 8:54 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-08-01 0:20 [RFC PATCH] [MTD] [OneNAND] Cache Read support Kyungmin Park
2007-08-01 6:24 ` Adrian Hunter
2007-08-01 7:09 ` Kyungmin Park
2007-08-01 8:52 ` Adrian Hunter
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox