Skip to contentSkip to conversation

OneNAND MTD support

PATCH New Kyungmin Park 2 participants 3 messages Aug 25, 2005 – Aug 27, 2005 1 message not in the archive

Subsystems (3)
lore
Share & tools
lore

A message that is not in the archive (sent off-list or not yet received): [email protected]

Kyungmin Park

author maintainer
#1 lore raw

I'm sorry to bother you

It's my mistake. I'm not delete block, and page parameters.
At first implementation I used the block and page address scheme instead of virtual address.

Simply delete block and page parameters.

And here's one total patch including previous three patches plus some minor patches.

If do you have any question. Please let me know

Thanks

Kyungmin Park

Quoted 34 lines

-----Original Message-----
From: Bernhard Priewasser [mailto:[email protected]]
Sent: Thursday, August 25, 2005 5:54 PM
To: [email protected]; [email protected]
Subject: Re: [PATCH] OneNAND MTD support

Hi Kyungmin,

when turning the "Verify OneNAND page write" on (make xconfig), OneNAND
module does not compile:

drivers/mtd/onenand/onenand_base.c: In function `onenand_write_ecc':
drivers/mtd/onenand/onenand_base.c:819: error: `block' undeclared (first
use in this function) drivers/mtd/onenand/onenand_base.c:819: error: (Each undeclared identifier is reported only once drivers/mtd/onenand/onenand_base.c:819: error: for each function it appears in.)
drivers/mtd/onenand/onenand_base.c:819: error: `page' undeclared (first
use in this function)
drivers/mtd/onenand/onenand_base.c: In function `onenand_writev_ecc':
drivers/mtd/onenand/onenand_base.c:1028: error: block' undeclared (first use in this function) drivers/mtd/onenand/onenand_base.c:1028: error: page' undeclared (first
use in this function)
make[3]: *** [drivers/mtd/onenand/onenand_base.o] Error 1 make[2]: *** [drivers/mtd/onenand] Error 2
make[1]: *** [drivers/mtd] Error 2
make: *** [drivers] Error 2

Quoted 5 lines

Where should onenand_write_ecc() get block and page from?

Bernhard

drivers/mtd/onenand/Kconfig +6 -0
@@ -29,4 +29,10 @@ config MTD_ONENAND_OMAP
 	help
 	  Support for OneNAND flash on TI OMAP board.
 
+config MTD_ONENAND_SYNC_READ
+	bool "OneNAND Sync. Burst Read Support"
+	depends on ARCH_OMAP
+	help
+	  This enables support for Sync. Burst Read.
+
 endmenu
drivers/mtd/onenand/Makefile +3 -1
@@ -3,7 +3,9 @@
 #
 
 # Core functionality.
-obj-$(CONFIG_MTD_ONENAND)		+= onenand_base.o
+obj-$(CONFIG_MTD_ONENAND)		+= onenand.o
 
 # Board specific.
 obj-$(CONFIG_MTD_ONENAND_OMAP)		+= omap-onenand.o
+
+onenand-objs = onenand_base.o onenand_bbt.o
drivers/mtd/onenand/omap-onenand.c +96 -127

270 lines not on this page · raw message

drivers/mtd/onenand/onenand_base.c +127 -27

257 lines not on this page · raw message

drivers/mtd/onenand/onenand_bbt.c new file +246 -0

246 lines not on this page · raw message

include/linux/mtd/bbm.h new file +122 -0

122 lines not on this page · raw message

include/linux/mtd/onenand.h +19 -0
@@ -14,8 +14,10 @@
 
 #include <linux/spinlock.h>
 #include <linux/mtd/onenand_regs.h>
+#include <linux/mtd/bbm.h>
 
 #define MAX_BUFFERRAM		2
+#define MAX_ONENAND_PAGESIZE	(2048 + 64)
 
 /* Scan and identify a OneNAND device */
 extern int onenand_scan(struct mtd_info *mtd, int max_chips);
@@ -67,10 +69,14 @@ struct onenand_bufferram {
  * @param wait		[REPLACEABLE] hardware specific function for wait on ready
  * @param read_bufferram	[REPLACEABLE] hardware specific function for BufferRAM Area
  * @param write_bufferram	[REPLACEABLE] hardware specific function for BufferRAM Area
+ * @param read_word	[REPLACEABLE] hardware specific function for read register of OneNAND
+ * @param write_word	[REPLACEABLE] hardware specific function for write register of OneNAND
+ * @param scan_bbt	[REPLACEALBE] hardware specific function for scaning Bad block Table
  * @param chip_lock	[INTERN] spinlock used to protect access to this structure and the chip
  * @param wq		[INTERN] wait queue to sleep on if a OneNAND operation is in progress
  * @param state		[INTERN] the current state of the OneNAND device
  * @param autooob	[REPLACEABLE] the default (auto)placement scheme
+ * @param bbm		[REPLACEABLE] pointer to Bad Block Management 
  * @param priv		[OPTIONAL] pointer to private chip date
  */
 struct onenand_chip {
@@ -95,6 +101,9 @@ struct onenand_chip {
 			const unsigned char *buffer, int offset, size_t count);
 	unsigned short (*read_word)(void __iomem *addr);
 	void (*write_word)(unsigned short value, void __iomem *addr);
+	void (*mmcontrol)(struct mtd_info *mtd, int sync_read);
+	int (*block_markbad)(struct mtd_info *mtd, loff_t ofs);
+	int (*scan_bbt)(struct mtd_info *mtd);
 
 	spinlock_t		chip_lock;
 	wait_queue_head_t	wq;
@@ -102,13 +111,23 @@ struct onenand_chip {
 
 	struct nand_oobinfo	*autooob;
 
+	void 			*bbm;
+
 	void			*priv;
 };
 
+/*
+ * Helper macros
+ */
 #define ONENAND_CURRENT_BUFFERRAM(this)		(this->bufferram_index)
 #define ONENAND_NEXT_BUFFERRAM(this)		(this->bufferram_index ^ 1)
 #define ONENAND_SET_NEXT_BUFFERRAM(this)	(this->bufferram_index ^= 1)
 
+#define ONENAND_GET_SYS_CFG1(this)					\
+	(this->read_word(this->base + ONENAND_REG_SYS_CFG1))
+#define ONENAND_SET_SYS_CFG1(v, this)					\
+	(this->write_word(v, this->base + ONENAND_REG_SYS_CFG1))
+
 /*
  * Options bits
  */
include/linux/mtd/onenand_regs.h +15 -2
@@ -121,8 +121,21 @@
  * System Configuration 1 Register F221h (R, R/W)
  */
 #define ONENAND_SYS_CFG1_SYNC_READ	(1 << 15)
-#define ONENAND_SYS_CFG1_BRL		(1 << 12)
-#define ONENAND_SYS_CFG1_BL		(1 << 9)
+#define ONENAND_SYS_CFG1_BRL_7		(7 << 12)
+#define ONENAND_SYS_CFG1_BRL_6		(6 << 12)
+#define ONENAND_SYS_CFG1_BRL_5		(5 << 12)
+#define ONENAND_SYS_CFG1_BRL_4		(4 << 12)
+#define ONENAND_SYS_CFG1_BRL_3		(3 << 12)
+#define ONENAND_SYS_CFG1_BRL_10		(2 << 12)
+#define ONENAND_SYS_CFG1_BRL_9		(1 << 12)
+#define ONENAND_SYS_CFG1_BRL_8		(0 << 12)
+#define ONENAND_SYS_CFG1_BRL_SHIFT	(12)
+#define ONENAND_SYS_CFG1_BL_32		(4 << 9)
+#define ONENAND_SYS_CFG1_BL_16		(3 << 9)
+#define ONENAND_SYS_CFG1_BL_8		(2 << 9)
+#define ONENAND_SYS_CFG1_BL_4		(1 << 9)
+#define ONENAND_SYS_CFG1_BL_CONT	(0 << 9)
+#define ONENAND_SYS_CFG1_BL_SHIFT	(9)
 #define ONENAND_SYS_CFG1_NO_ECC		(1 << 8)
 #define ONENAND_SYS_CFG1_RDY		(1 << 7)
 #define ONENAND_SYS_CFG1_INT		(1 << 6)
include/asm-arm/mach/flash.h +13 -0
@@ -11,6 +11,7 @@
 #define ASMARM_MACH_FLASH_H
 
 struct mtd_partition;
+struct mtd_info;
 
 /*
  * map_name:   the map probe function name
@@ -31,4 +32,16 @@ struct flash_platform_data {
        unsigned int    nr_parts;
 };
 
+/**
+ * struct onenand_platform_data - platform data describing OneNAND flash banks
+ * @param mmcontrol    Handle memroy control for Sync. Burst Read
+ * @param parts                optional array of mtd_partitions for static partioning
+ * @param nr_parts     number of mtd_partitions for static partitioning
+ */
+struct onenand_platform_data {
+       void            (*mmcontrol)(struct mtd_info *mtd, int sync_read);
+       struct mtd_partition *parts;
+       unsigned int    nr_parts;
+};
+
 #endif
#2 lore raw
Quoted 1 line

I'm sorry to bother you

No, I'm sorry to bother YOU. You did the work, and you did it good, so you bother noone at all.

Quoted 2 lines

And here's one total patch including previous three patches plus some minor patches.

It patches and compiles error free on a 2.6.11 kernel with recent MTD.

Quoted 1 line

If do you have any question. Please let me know

I will...

Regards
Bernhard

author maintainer
#3 lore raw

PATCH 1/1 OneNAND: simulator support

Hi

This patch enables OneNAND simulator on OneNAND MTD.

Any comments are welcome.

Begards.

Kyungmin Park

--

drivers/mtd/onenand/Kconfig +7 -0
@@ -35,4 +35,11 @@ config MTD_ONENAND_SYNC_READ
 	help
 	  This enables support for Sync. Burst Read.
 
+config MTD_ONENAND_SIM
+	tristate "Support for OneNAND flash simulator"
+	depends on MTD_ONENAND
+	help
+	  The simulator may simulate verious OneNAND flash chips for the
+          MTD onenand layer.
+
 endmenu
drivers/mtd/onenand/Makefile +3 -0
@@ -8,4 +8,7 @@ obj-$(CONFIG_MTD_ONENAND)		+= onenand.o
 # Board specific.
 obj-$(CONFIG_MTD_ONENAND_OMAP)		+= omap-onenand.o
 
+# Simulator
+obj-$(CONFIG_MTD_ONENAND_SIM)		+= onenand_sim.o
+
 onenand-objs = onenand_base.o onenand_bbt.o
(quoted diff) +0 -0

b/drivers/mtd/onenand/onenand_sim.c
new file mode 100644

drivers/mtd/onenand/onenand_sim.c new file +97 -0

98 lines not on this page · raw message

this);
+ break;
+
+ default:
+ break;
+ }
+}
+
+/**
+ * onenand_bootram_handle - Handle BootRAM area
+ * @param this OneNAND device structure
+ * @param cmd The command to be sent
+ *
+ * Emulate BootRAM area. It is possible to do basic operation using BootRAM.
+ */
+static void onenand_bootram_handle(struct onenand_chip *this, int cmd) +{
+ switch (cmd) {
+ case ONENAND_CMD_READID:
+ writew(manuf_id, this->base);
+ writew(device_id, this->base + 2);
+ writew(version_id, this->base + 4);
+ break;
+
+ default:
+ /* REVIST: Handle other commands */
+ break;
+ }
+}
+
+/**
+ * onenand_update_interrupt - Set interrupt register
+ * @param this OneNAND device structure
+ * @param cmd The command to be sent
+ *
+ * Update interrupt register. The status is depends on command.
+ */
+static void onenand_update_interrupt(struct onenand_chip *this, int cmd) +{
+ int interrupt = ONENAND_INT_MASTER;
+
+ switch (cmd) {
+ case ONENAND_CMD_READ:
+ case ONENAND_CMD_READOOB:
+ interrupt |= ONENAND_INT_READ;
+ break;
+
+ case ONENAND_CMD_PROG:
+ case ONENAND_CMD_PROGOOB:
+ interrupt |= ONENAND_INT_WRITE;
+ break;
+
+ case ONENAND_CMD_ERASE:
+ interrupt |= ONENAND_INT_ERASE;
+ break;
+
+ case ONENAND_CMD_RESET:
+ interrupt |= ONENAND_INT_RESET;
+ break;
+
+ default:
+ break;
+ }
+
+ writew(interrupt, this->base + ONENAND_REG_INTERRUPT);
+}
+
+/**
+ * onenand_check_overwrite - Check over-write if happend
+ * @param dest The destination pointer
+ * @param src The source pointer
+ * @param count The length to be check
+ * @return 0 on same, otherwise 1
+ *
+ * Compare the source with destination
+ */
+static int onenand_check_overwrite(void *dest, void *src, size_t count) +{
+ unsigned int *s = (unsigned int *) src;
+ unsigned int *d = (unsigned int *) dest;
+ int i;
+ count >>= 2;
+
+ for (i = 0; i < count; i++)
+ if ((*s++ ^ *d++) != 0)
+ return 1;
+
+ return 0;
+}
+
+/**
+ * onenand_data_handle - Handle OneNAND Core and DataRAM
+ * @param this OneNAND device structure
+ * @param cmd The command to be sent
+ * @param dataram Which dataram used
+ * @param offset The offset to OneNAND Core
+ *
+ * Copy data from OneNAND Core to DataRAM (read)
+ * Copy data from DataRAM to OneNAND Core (write)
+ * Erase the OneNAND Core (erase)
+ */
+static void onenand_data_handle(struct onenand_chip *this, int cmd,
+ int dataram, unsigned int offset)
+{
+ struct onenand_flash *flash = this->priv;
+ int main_offset, spare_offset;
+ void __iomem *src;
+ void __iomem *dest;
+
+ if (dataram) {
+ main_offset = onenand_sim->oobblock;
+ spare_offset = onenand_sim->oobsize;
+ } else {
+ main_offset = 0;
+ spare_offset = 0;
+ }
+
+ switch (cmd) {
+ case ONENAND_CMD_READ:
+ src = ONENAND_CORE(flash) + offset;
+ dest = ONENAND_MAIN_AREA(this, main_offset);
+ memcpy(dest, src, onenand_sim->oobblock);
+ /* Fall through */
+
+ case ONENAND_CMD_READOOB:
+ src = ONENAND_CORE(flash) + this->chipsize + (offset >> 5);
+ dest = ONENAND_SPARE_AREA(this, spare_offset);
+ memcpy(dest, src, onenand_sim->oobsize);
+ break;
+
+ case ONENAND_CMD_PROG:
+ src = ONENAND_MAIN_AREA(this, main_offset);
+ dest = ONENAND_CORE(flash) + offset;
+ if (memcmp(dest, ffchars, onenand_sim->oobblock) &&
+ onenand_check_overwrite(dest, src,
onenand_sim->oobblock))
+ printk(KERN_ERR "over-write happend at 0x%08x\n",
offset);
+ memcpy(dest, src, onenand_sim->oobblock);
+ /* Fall through */
+
+ case ONENAND_CMD_PROGOOB:
+ src = ONENAND_SPARE_AREA(this, spare_offset);
+ /* Check all data is 0xff chars */
+ if (!memcmp(src, ffchars, onenand_sim->oobsize))
+ break;
+
+ dest = ONENAND_CORE(flash) + this->chipsize + (offset >> 5);
+ if (memcmp(dest, ffchars, onenand_sim->oobsize) &&
+ onenand_check_overwrite(dest, src,
onenand_sim->oobsize))
+ printk(KERN_ERR "OOB: over-write happend at
0x%08x\n", offset);
+ memcpy(dest, src, onenand_sim->oobsize);
+ break;
+
+ case ONENAND_CMD_ERASE:
+ memset(ONENAND_CORE(flash) + offset, 0xff, (1 <<
this->erase_shift));
+ break;
+
+ default:
+ break;
+ }
+}
+
+/**
+ * onenand_command_handle - Handle command
+ * @param this OneNAND device structure
+ * @param cmd The command to be sent
+ *
+ * Emulate OneNAND command.
+ */
+static void onenand_command_handle(struct onenand_chip *this, int cmd) +{
+ unsigned long offset = 0;
+ int block = -1, page = -1, bufferram = -1;
+ int dataram = 0;
+
+ switch (cmd) {
+ case ONENAND_CMD_UNLOCK:
+ case ONENAND_CMD_LOCK:
+ case ONENAND_CMD_LOCK_TIGHT:
+ onenand_lock_handle(this, cmd);
+ break;
+
+ case ONENAND_CMD_BUFFERRAM:
+ /* Do nothing */
+ return;
+
+ default:
+ block = (int) readw(this->base +
ONENAND_REG_START_ADDRESS1);
+ if (block & (1 << ONENAND_DDP_SHIFT)) {
+ block &= ~(1 << ONENAND_DDP_SHIFT);
+ /* The half of chip block */
+ block += this->chipsize >> (this->erase_shift + 1);
+ }
+ if (cmd == ONENAND_CMD_ERASE)
+ break;
+
+ page = (int) readw(this->base + ONENAND_REG_START_ADDRESS8);
+ page = (page >> ONENAND_FPA_SHIFT);
+ bufferram = (int) readw(this->base +
ONENAND_REG_START_BUFFER);
+ bufferram >>= ONENAND_BSA_SHIFT;
+ bufferram &= ONENAND_BSA_DATARAM1;
+ dataram = (bufferram == ONENAND_BSA_DATARAM1) ? 1 : 0;
+ break;
+ }
+
+ if (block != -1)
+ offset += block << this->erase_shift;
+
+ if (page != -1)
+ offset += page << this->page_shift;
+
+ onenand_data_handle(this, cmd, dataram, offset);
+
+ onenand_update_interrupt(this, cmd);
+}
+
+/**
+ * onenand_writew - [OneNAND Interface] Emulate write operation
+ * @param value value to write
+ * @param addr address to write
+ *
+ * Write OneNAND reigser with value
+ */
+static void onenand_writew(unsigned short value, void __iomem *addr) +{
+ struct onenand_chip *this = onenand_sim->priv;
+
+ /* BootRAM handling */
+ if (addr < this->base + ONENAND_DATARAM) {
+ onenand_bootram_handle(this, value);
+ return;
+ }
+ /* Command handling */
+ if (addr == this->base + ONENAND_REG_COMMAND)
+ onenand_command_handle(this, value);
+
+ writew(value, addr);
+}
+
+/**
+ * flash_init - Initialize OneNAND simulator
+ * @param flash OneNAND simulaotr data strucutres
+ *
+ * Initialize OneNAND simulator.
+ */
+static int __init flash_init(struct onenand_flash *flash)
+{
+ int density, size;
+ int buffer_size;
+
+ flash->base = kmalloc(SZ_128K, GFP_KERNEL);
+ if (!flash->base) {
+ printk(KERN_ERR "Unalbe to allocate base address.\n");
+ return -ENOMEM;
+ }
+
+ memset(flash->base, 0, SZ_128K);
+
+ density = device_id >> ONENAND_DEVICE_DENSITY_SHIFT;
+ size = ((16 << 20) << density);
+
+ ONENAND_CORE(flash) = vmalloc(size + (size >> 5));
+ if (!ONENAND_CORE(flash)) {
+ printk(KERN_ERR "Unalbe to allocate nand core address.\n");
+ kfree(flash->base);
+ return -ENOMEM;
+ }
+
+ memset(ONENAND_CORE(flash), 0xff, size + (size >> 5));
+
+ /* Setup registers */
+ writew(manuf_id, flash->base + ONENAND_REG_MANUFACTURER_ID);
+ writew(device_id, flash->base + ONENAND_REG_DEVICE_ID);
+ writew(version_id, flash->base + ONENAND_REG_VERSION_ID);
+
+ if (density < 2)
+ buffer_size = 0x0400; /* 1KB page */
+ else
+ buffer_size = 0x0800; /* 2KB page */
+ writew(buffer_size, flash->base + ONENAND_REG_DATA_BUFFER_SIZE);
+
+ return 0;
+}
+
+/**
+ * flash_exit - Clean up OneNAND simulator
+ * @param flash OneNAND simulaotr data strucutres
+ *
+ * Clean up OneNAND simulator.
+ */
+static void flash_exit(struct onenand_flash *flash)
+{
+ vfree(ONENAND_CORE(flash));
+ kfree(flash->base);
+ kfree(flash);
+}
+
+static int __init onenand_sim_init(void)
+{
+ struct onenand_chip *this;
+ struct onenand_flash *flash;
+ int len;
+
+ /* Allocate all 0xff chars pointer */
+ ffchars = kmalloc(MAX_ONENAND_PAGESIZE, GFP_KERNEL);
+ if (!ffchars) {
+ printk(KERN_ERR "Unable to allocate ff chars.\n");
+ return -ENOMEM;
+ }
+ memset(ffchars, 0xff, MAX_ONENAND_PAGESIZE);
+
+ len = sizeof(struct mtd_info) + sizeof(struct onenand_chip) + sizeof
(struct onenand_flash);
+
+ /* Allocate OneNAND simulator mtd pointer */
+ onenand_sim = kmalloc(len, GFP_KERNEL);
+ if (!onenand_sim) {
+ printk(KERN_ERR "Unable to allocate core structures.\n");
+ kfree(ffchars);
+ return -ENOMEM;
+ }
+
+ memset(onenand_sim, 0, len);
+
+ this = (struct onenand_chip *) (onenand_sim + 1);
+ /* Override write_word function */
+ this->write_word = onenand_writew;
+
+ flash = (struct onenand_flash *) (this + 1);
+
+ if (flash_init(flash)) {
+ printk(KERN_ERR "Unable to allocat flash.\n");
+ kfree(ffchars);
+ kfree(onenand_sim);
+ return -ENOMEM;
+ }
+
+ this->base = flash->base;
+ this->priv = flash;
+ onenand_sim->priv = this;
+
+ if (onenand_scan(onenand_sim, 1)) {
+ kfree(ffchars);
+ kfree(onenand_sim);
+ flash_exit(flash);
+ return -ENXIO;
+ }
+
+ add_mtd_device(onenand_sim);
+
+ return 0;
+}
+
+static void __exit onenand_sim_exit(void)
+{
+ struct onenand_chip *this = onenand_sim->priv;
+ struct onenand_flash *flash = this->priv;
+
+ kfree(ffchars);
+ onenand_release(onenand_sim);
+ flash_exit(flash);
+ kfree(onenand_sim);
+}
+
+module_init(onenand_sim_init); +module_exit(onenand_sim_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Kyungmin Park <[email protected]>"); +MODULE_DESCRIPTION("The OneNAND flash simulator");