X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=drivers%2Fmtd%2Fonenand%2Fonenand_sim.c;h=d64200b7c94bfd4c0caf5dc782ba2146d0f584f9;hb=a14ad05f47b55ea84136eb4da43ea96fa469326a;hp=cb376b20695329fdf29967472fa595e80d403e48;hpb=405c829f98d216925de00af2ee52f969f2c2891c;p=linux-2.6 diff --git a/drivers/mtd/onenand/onenand_sim.c b/drivers/mtd/onenand/onenand_sim.c index cb376b2069..d64200b7c9 100644 --- a/drivers/mtd/onenand/onenand_sim.c +++ b/drivers/mtd/onenand/onenand_sim.c @@ -1,42 +1,48 @@ /* - * linux/drivers/mtd/onenand/simulator.c + * linux/drivers/mtd/onenand/onenand_sim.c * * The OneNAND simulator * - * Copyright(c) 2005 Samsung Electronics + * Copyright © 2005-2007 Samsung Electronics * Kyungmin Park + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. */ -#include +#include #include #include #include #include +#include #include -#include -#include +#include #ifndef CONFIG_ONENAND_SIM_MANUFACTURER -#define CONFIG_ONENAND_SIM_MANUFACTURER 0xec +#define CONFIG_ONENAND_SIM_MANUFACTURER 0xec #endif #ifndef CONFIG_ONENAND_SIM_DEVICE_ID -#define CONFIG_ONENAND_SIM_DEVICE_ID 0x04 +#define CONFIG_ONENAND_SIM_DEVICE_ID 0x04 #endif #ifndef CONFIG_ONENAND_SIM_VERSION_ID -#define CONFIG_ONENAND_SIM_VERSION_ID 0x1e +#define CONFIG_ONENAND_SIM_VERSION_ID 0x1e #endif -static int manuf_id = CONFIG_ONENAND_SIM_MANUFACTURER; -static int device_id = CONFIG_ONENAND_SIM_DEVICE_ID; -static int version_id = CONFIG_ONENAND_SIM_VERSION_ID; +static int manuf_id = CONFIG_ONENAND_SIM_MANUFACTURER; +static int device_id = CONFIG_ONENAND_SIM_DEVICE_ID; +static int version_id = CONFIG_ONENAND_SIM_VERSION_ID; struct onenand_flash { - void __iomem *base; - void __iomem *data; + void __iomem *base; + void __iomem *data; }; -#define ONENAND_CORE(flash) (flash->data) +#define ONENAND_CORE(flash) (flash->data) +#define ONENAND_CORE_SPARE(flash, this, offset) \ + ((flash->data) + (this->chipsize) + (offset >> 5)) #define ONENAND_MAIN_AREA(this, offset) \ (this->base + ONENAND_DATARAM + offset) @@ -51,21 +57,42 @@ struct onenand_flash { (writew(v, this->base + ONENAND_REG_WP_STATUS)) /* It has all 0xff chars */ +#define MAX_ONENAND_PAGESIZE (2048 + 64) static unsigned char *ffchars; +static struct mtd_partition os_partitions[] = { + { + .name = "OneNAND simulator partition", + .offset = 0, + .size = MTDPART_SIZ_FULL, + }, +}; + /* * OneNAND simulator mtd */ -struct mtd_info *onenand_sim; +struct onenand_info { + struct mtd_info mtd; + struct mtd_partition *parts; + struct onenand_chip onenand; + struct onenand_flash flash; +}; + +static struct onenand_info *info; +#define DPRINTK(format, args...) \ +do { \ + printk(KERN_DEBUG "%s[%d]: " format "\n", __func__, \ + __LINE__, ##args); \ +} while (0) /** * onenand_lock_handle - Handle Lock scheme - * @param this OneNAND device structure - * @param cmd The command to be sent + * @this: OneNAND device structure + * @cmd: The command to be sent * * Send lock command to OneNAND device. - * The lock scheme is depends on chip type. + * The lock scheme depends on chip type. */ static void onenand_lock_handle(struct onenand_chip *this, int cmd) { @@ -73,8 +100,8 @@ static void onenand_lock_handle(struct onenand_chip *this, int cmd) int status; status = ONENAND_GET_WP_STATUS(this); - block_lock_scheme = !(this->options & ONENAND_CONT_LOCK); - + block_lock_scheme = !(this->options & ONENAND_HAS_CONT_LOCK); + switch (cmd) { case ONENAND_CMD_UNLOCK: if (block_lock_scheme) @@ -104,8 +131,8 @@ static void onenand_lock_handle(struct onenand_chip *this, int cmd) /** * onenand_bootram_handle - Handle BootRAM area - * @param this OneNAND device structure - * @param cmd The command to be sent + * @this: OneNAND device structure + * @cmd: The command to be sent * * Emulate BootRAM area. It is possible to do basic operation using BootRAM. */ @@ -126,10 +153,10 @@ static void onenand_bootram_handle(struct onenand_chip *this, int cmd) /** * onenand_update_interrupt - Set interrupt register - * @param this OneNAND device structure - * @param cmd The command to be sent + * @this: OneNAND device structure + * @cmd: The command to be sent * - * Update interrupt register. The status is depends on command. + * Update interrupt register. The status depends on command. */ static void onenand_update_interrupt(struct onenand_chip *this, int cmd) { @@ -162,11 +189,12 @@ static void onenand_update_interrupt(struct onenand_chip *this, int cmd) } /** - * 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 + * onenand_check_overwrite - Check if over-write happened + * @dest: The destination pointer + * @src: The source pointer + * @count: The length to be check + * + * Returns: 0 on same, otherwise 1 * * Compare the source with destination */ @@ -175,8 +203,8 @@ 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; + count >>= 2; for (i = 0; i < count; i++) if ((*s++ ^ *d++) != 0) return 1; @@ -186,26 +214,28 @@ static int onenand_check_overwrite(void *dest, void *src, size_t count) /** * 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 + * @this: OneNAND device structure + * @cmd: The command to be sent + * @dataram: Which dataram used + * @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) + int dataram, unsigned int offset) { + struct mtd_info *mtd = &info->mtd; struct onenand_flash *flash = this->priv; int main_offset, spare_offset; void __iomem *src; void __iomem *dest; + unsigned int i; if (dataram) { - main_offset = onenand_sim->oobblock; - spare_offset = onenand_sim->oobsize; + main_offset = mtd->writesize; + spare_offset = mtd->oobsize; } else { main_offset = 0; spare_offset = 0; @@ -215,39 +245,48 @@ static void onenand_data_handle(struct onenand_chip *this, int cmd, case ONENAND_CMD_READ: src = ONENAND_CORE(flash) + offset; dest = ONENAND_MAIN_AREA(this, main_offset); - memcpy(dest, src, onenand_sim->oobblock); + memcpy(dest, src, mtd->writesize); /* Fall through */ case ONENAND_CMD_READOOB: - src = ONENAND_CORE(flash) + this->chipsize + (offset >> 5); + src = ONENAND_CORE_SPARE(flash, this, offset); dest = ONENAND_SPARE_AREA(this, spare_offset); - memcpy(dest, src, onenand_sim->oobsize); + memcpy(dest, src, mtd->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); + /* To handle partial write */ + for (i = 0; i < (1 << mtd->subpage_sft); i++) { + int off = i * this->subpagesize; + if (!memcmp(src + off, ffchars, this->subpagesize)) + continue; + if (memcmp(dest + off, ffchars, this->subpagesize) && + onenand_check_overwrite(dest + off, src + off, this->subpagesize)) + printk(KERN_ERR "over-write happend at 0x%08x\n", offset); + memcpy(dest + off, src + off, this->subpagesize); + } /* 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)) + if (!memcmp(src, ffchars, mtd->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); + dest = ONENAND_CORE_SPARE(flash, this, offset); + if (memcmp(dest, ffchars, mtd->oobsize) && + onenand_check_overwrite(dest, src, mtd->oobsize)) + printk(KERN_ERR "OOB: over-write happend at 0x%08x\n", + offset); + memcpy(dest, src, mtd->oobsize); break; case ONENAND_CMD_ERASE: - memset(ONENAND_CORE(flash) + offset, 0xff, (1 << this->erase_shift)); + memset(ONENAND_CORE(flash) + offset, 0xff, mtd->erasesize); + memset(ONENAND_CORE_SPARE(flash, this, offset), 0xff, + (mtd->erasesize >> 5)); break; default: @@ -257,8 +296,8 @@ static void onenand_data_handle(struct onenand_chip *this, int cmd, /** * onenand_command_handle - Handle command - * @param this OneNAND device structure - * @param cmd The command to be sent + * @this: OneNAND device structure + * @cmd: The command to be sent * * Emulate OneNAND command. */ @@ -272,6 +311,7 @@ static void onenand_command_handle(struct onenand_chip *this, int cmd) case ONENAND_CMD_UNLOCK: case ONENAND_CMD_LOCK: case ONENAND_CMD_LOCK_TIGHT: + case ONENAND_CMD_UNLOCK_ALL: onenand_lock_handle(this, cmd); break; @@ -311,14 +351,14 @@ static void onenand_command_handle(struct onenand_chip *this, int cmd) /** * onenand_writew - [OneNAND Interface] Emulate write operation - * @param value value to write - * @param addr address to write + * @value: value to write + * @addr: address to write * - * Write OneNAND reigser with value + * Write OneNAND register with value */ -static void onenand_writew(unsigned short value, void __iomem *addr) +static void onenand_writew(unsigned short value, void __iomem * addr) { - struct onenand_chip *this = onenand_sim->priv; + struct onenand_chip *this = info->mtd.priv; /* BootRAM handling */ if (addr < this->base + ONENAND_DATARAM) { @@ -334,7 +374,7 @@ static void onenand_writew(unsigned short value, void __iomem *addr) /** * flash_init - Initialize OneNAND simulator - * @param flash OneNAND simulaotr data strucutres + * @flash: OneNAND simulator data strucutres * * Initialize OneNAND simulator. */ @@ -343,20 +383,18 @@ static int __init flash_init(struct onenand_flash *flash) int density, size; int buffer_size; - flash->base = kmalloc(SZ_128K, GFP_KERNEL); + flash->base = kzalloc(131072, GFP_KERNEL); if (!flash->base) { - printk(KERN_ERR "Unalbe to allocate base address.\n"); + printk(KERN_ERR "Unable 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"); + printk(KERN_ERR "Unable to allocate nand core address.\n"); kfree(flash->base); return -ENOMEM; } @@ -369,17 +407,17 @@ static int __init flash_init(struct onenand_flash *flash) writew(version_id, flash->base + ONENAND_REG_VERSION_ID); if (density < 2) - buffer_size = 0x0400; /* 1KB page */ + buffer_size = 0x0400; /* 1KiB page */ else - buffer_size = 0x0800; /* 2KB page */ + buffer_size = 0x0800; /* 2KiB 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 + * @flash: OneNAND simulator data structures * * Clean up OneNAND simulator. */ @@ -387,15 +425,10 @@ 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) { @@ -404,61 +437,59 @@ static int __init onenand_sim_init(void) } 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) { + info = kzalloc(sizeof(struct onenand_info), GFP_KERNEL); + if (!info) { 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); + info->onenand.write_word = onenand_writew; - if (flash_init(flash)) { - printk(KERN_ERR "Unable to allocat flash.\n"); + if (flash_init(&info->flash)) { + printk(KERN_ERR "Unable to allocate flash.\n"); kfree(ffchars); - kfree(onenand_sim); + kfree(info); return -ENOMEM; } - this->base = flash->base; - this->priv = flash; - onenand_sim->priv = this; + info->parts = os_partitions; + + info->onenand.base = info->flash.base; + info->onenand.priv = &info->flash; - if (onenand_scan(onenand_sim, 1)) { + info->mtd.name = "OneNAND simulator"; + info->mtd.priv = &info->onenand; + info->mtd.owner = THIS_MODULE; + + if (onenand_scan(&info->mtd, 1)) { + flash_exit(&info->flash); kfree(ffchars); - kfree(onenand_sim); - flash_exit(flash); + kfree(info); return -ENXIO; } - add_mtd_device(onenand_sim); + add_mtd_partitions(&info->mtd, info->parts, ARRAY_SIZE(os_partitions)); return 0; } static void __exit onenand_sim_exit(void) { - struct onenand_chip *this = onenand_sim->priv; + struct onenand_chip *this = info->mtd.priv; struct onenand_flash *flash = this->priv; - kfree(ffchars); - onenand_release(onenand_sim); + onenand_release(&info->mtd); flash_exit(flash); - kfree(onenand_sim); + kfree(ffchars); + kfree(info); } module_init(onenand_sim_init); module_exit(onenand_sim_exit); -MODULE_LICENSE("GPL"); MODULE_AUTHOR("Kyungmin Park "); MODULE_DESCRIPTION("The OneNAND flash simulator"); +MODULE_LICENSE("GPL");