MTD lowlevel driver for SCH-M100
Yong-iL Joh
tolkien at mizi.com
Mon Aug 7 00:04:34 EDT 2000
we are working on SAMSUNG smartphone SCH-M100.
this is low level mtd driver for Intel BootBlock FlashROM (28F160B3)
because SAMSUNG combine two 16bit-wide Flashes in parellel way,
it seems to be 32bit-wide FlashROM.
--
Joh, Yong-iL
E-mail: tolkien at nownuri.net tolkien at mizi.com
-------------- next part --------------
diff -ruN mtd/kernel/Config.in linux/drivers/mtd/Config.in
--- mtd/kernel/Config.in Fri Aug 4 01:04:16 2000
+++ linux/drivers/mtd/Config.in Mon Aug 7 12:20:41 2000
@@ -29,6 +29,7 @@
int 'Device size in kB' CONFIG_MTDRAM_TOTAL_SIZE 4096
int 'Size of the erase sectors in kB' CONFIG_MTDRAM_ERASE_SIZE 128
fi
+ dep_tristate ' Flash chips on SCH-M100' CONFIG_MTD_SCHM100 $CONFIG_MTD
comment 'MTD drivers for mapped chips'
dep_tristate ' Common Flash Interface (CFI) support' CONFIG_MTD_CFI $CONFIG_MTD
diff -ruN mtd/kernel/Makefile linux/drivers/mtd/Makefile
--- mtd/kernel/Makefile Tue Aug 1 01:04:11 2000
+++ linux/drivers/mtd/Makefile Mon Aug 7 12:20:36 2000
@@ -57,6 +57,7 @@
obj-$(CONFIG_MTD_SLRAM) += slram.o
obj-$(CONFIG_MTD_PMC551) += pmc551.o
obj-$(CONFIG_MTD_MTDRAM) += mtdram.o
+obj-$(CONFIG_MTD_SCHM100) += schm100.o
# Chip drivers
obj-$(CONFIG_MTD_JEDEC) += jedec.o
diff -ruN mtd/kernel/mtdcore.c linux/drivers/mtd/mtdcore.c
--- mtd/kernel/mtdcore.c Sat Aug 5 01:04:12 2000
+++ linux/drivers/mtd/mtdcore.c Mon Aug 7 12:20:33 2000
@@ -1,5 +1,5 @@
/*
- * $Id: mtdcore.c,v 1.14 2000/08/03 16:16:53 dvrabel Exp $
+ * $Id: mtdcore.c,v 1.7 2000/08/07 02:37:14 tolkien Exp $
*
* Core registration and callback routines for MTD
* drivers and users.
@@ -65,12 +65,15 @@
#ifdef CONFIG_MTD_PMC551
extern int init_pmc551(void);
#endif
-#ifdef CONFIG_MTD_NORA
-extern int init_nora(void);
+#ifdef CONFIG_MTD_SCHM100
+extern int init_schm100_mtd(void);
#endif
#ifdef CONFIG_MTD_SBC_MEDIAGX
extern int init_sbc_mediagx(void);
#endif
+#ifdef CONFIG_MTD_NORA
+extern int init_nora(void);
+#endif
#ifdef CONFIG_FTL
extern int init_ftl(void);
#endif
@@ -416,12 +419,15 @@
#ifdef CONFIG_MTD_PMC551
init_pmc551();
#endif
-#ifdef CONFIG_MTD_NORA
- init_nora();
+#ifdef CONFIG_MTD_SCHM100
+ init_schm100_mtd();
#endif
#ifdef CONFIG_MTD_SBC_MEDIAGX
init_sbc_mediagx();
#endif
+#ifdef CONFIG_MTD_NORA
+ init_nora();
+#endif
#ifdef CONFIG_MTD_MTDRAM
init_mtdram();
#endif
@@ -495,5 +501,3 @@
module_init(init_mtd);
module_exit(cleanup_mtd);
#endif
-
-
diff -ruN mtd/kernel/schm100.c linux/drivers/mtd/schm100.c
--- mtd/kernel/schm100.c Thu Jan 1 09:00:00 1970
+++ linux/drivers/mtd/schm100.c Mon Aug 7 12:41:16 2000
@@ -0,0 +1,667 @@
+/*
+ * $Id: schm100.c,v 1.4 2000/08/07 02:37:14 tolkien Exp $
+ *
+ * Intel 3 volt Advanced Boot Block Flash Memory Device
+ * based in drivers/mtd/nora.c, drivers/mtd/cfi_cmd_0001.c
+ *
+ * Author:
+ * Yong-iL Joh <tolkien at mizi.com>
+ * Copyright 2000 Mizi Research
+ *
+ * License:
+ * As part of this driver was derrived from the slram.c driver it falls
+ * under the same license, which is GNU General Public License v2
+ *
+ * Description:
+ * This driver is intended to support the Boot Block Flash device from
+ * Intel Inc. in SAMSUNG SmartPhone SCH-M100. There are two Intel NOR
+ * 16bit-wide FlashROMs, but assembled in parallel, so we must use them
+ * as single 32bit-wide NOR FlashROMs. Therefore there is no
+ * consideration to multi-chips.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+
+#include <linux/malloc.h>
+#include <linux/delay.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/flashchip.h>
+#include <asm/arch/hardware.h>
+#include <asm/io.h>
+
+#include "schm100.h"
+
+/* FlashChip Info. */
+static struct flchip *chip;
+#define set_current_state(x) current->state = (x);
+
+inline static int schm100_flash_wait(unsigned long addr, struct wait_queue *wait_p,
+ unsigned long *timeo_p, const char *str) {
+ __u32 status;
+
+ retry:
+ spin_lock_bh(chip->mutex);
+
+ /* Check that the chip's ready to talk to us.
+ * Later, we can actually think about interrupting it
+ * if it's in FL_ERASING or FL_WRITING state.
+ * Not just yet, though.
+ */
+ switch (chip->state) {
+#if 0
+ case FL_ERASING:
+ case FL_WRITING:
+ /* Suspend the operation, set state to FL_xxx_SUSPENDED */
+#endif
+ case FL_CFI_QUERY:
+ case FL_JEDEC_QUERY:
+ case FL_READY:
+ __IOW(addr) = FLASH_READ_STATUS;
+ chip->state = FL_STATUS;
+
+ case FL_STATUS:
+ status = __IOW(addr);
+ *timeo_p = jiffies + HZ;
+
+ if (!(status & FLS_WRITE)) {
+ static int z=0;
+ /* Urgh. Chip not yet ready to talk to us. */
+ if (time_after(jiffies, *timeo_p)) {
+ spin_unlock_bh(chip->mutex);
+ printk("waiting for chip to be ready timed out in %s", str);
+ return -EIO;
+ }
+
+ /* Latency issues. Drop the lock, wait a while and retry */
+ spin_unlock_bh(chip->mutex);
+
+ z++;
+ if ( 0 && !(z % 100 ))
+ printk("chip not ready yet before %s. looping\n", str);
+
+ udelay(1);
+
+ goto retry;
+ }
+ break;
+
+ default:
+ printk("Waiting for chip, status = %d\n", chip->state);
+
+ /* Stick ourselves on a wait queue to be woken when
+ someone changes the status */
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ add_wait_queue(&chip->wq, wait_p);
+
+ spin_unlock_bh(chip->mutex);
+
+ schedule();
+ remove_wait_queue(&chip->wq, wait_p);
+
+ if(signal_pending(current))
+ return -EINTR;
+
+ *timeo_p = jiffies + HZ;
+
+ goto retry;
+ }
+
+ return 0;
+}
+
+inline static int schm100_flash_wait2(unsigned long addr, struct wait_queue *wait_p, \
+ unsigned long *timeo_p, flstate_t fls, int *z_p) {
+ __u32 status, condition;
+ char *str, *str2;
+
+ switch (fls) {
+ case FL_ERASING:
+ str = "erase";
+ str2 = "waiting for erase to complete timed out.";
+ condition = (FLS_VPP | FLS_ERASE | FLS_PROGRAM | FLS_LOCK);
+ break;
+ case FL_WRITING:
+ str = "program";
+ str2 = "waiting for chip to be ready timed out in read";
+ condition = (FLS_VPP | FLS_PROGRAM | FLS_LOCK);
+ break;
+ default:
+ str = "unknown";
+ str2 = "what else?";
+ condition = 0;
+ }
+
+ /* FIXME. Use a timer to check this, and return immediately. */
+ /* Once the state machine's known to be working I'll do that */
+
+ *z_p = 0;
+ while ( !( (status = __IOW(addr)) & FLS_WRITE ) ) {
+
+ if (chip->state != fls) {
+ /* Someone's suspended the erase/write. Sleep */
+ set_current_state(TASK_INTERRUPTIBLE);
+ add_wait_queue(&chip->wq, wait_p);
+
+ spin_unlock_bh(chip->mutex);
+ printk("%s suspended. Sleeping\n", str);
+
+ schedule();
+ remove_wait_queue(&chip->wq, wait_p);
+
+ if (signal_pending(current))
+ return -EINTR;
+
+ *timeo_p = jiffies + (HZ*2); /* FIXME */
+ spin_lock_bh(chip->mutex);
+ continue;
+ }
+
+ /* OK Still waiting */
+ if (time_after(jiffies, *timeo_p)) {
+ chip->state = FL_STATUS;
+ spin_unlock_bh(chip->mutex);
+ printk(str2);
+ return -EIO;
+ }
+
+ /* Latency issues. Drop the lock, wait a while and retry */
+ spin_unlock_bh(chip->mutex);
+
+ (*z_p)++;
+ if ( 0 && !((*z_p) % 100 ))
+ printk("chip not ready yet after %s. looping\n", str);
+
+ udelay(1);
+
+ spin_lock_bh(chip->mutex);
+ continue;
+ }
+
+ if (status & condition) {
+ __IOW(addr) = FLASH_CLEAR_STATUS;
+ __IOW(addr) = FLASH_READ_STATUS;
+ return status & condition;
+ }
+ return 0;
+}
+
+static int schm100_mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
+{
+ unsigned long timeo = jiffies + HZ, addr;
+ DECLARE_WAITQUEUE(wait, current);
+ int ret;
+
+ addr = from + (unsigned long)mtd->priv;
+ if (len > mtd->size - from) len = mtd->size - from;
+ if (len < 1) return -EINVAL;
+
+ ret = schm100_flash_wait(addr, &wait, &timeo, "read");
+ if (ret != 0) return ret;
+
+ __IOW(addr) = FLASH_READ_ARRAY;
+ chip->state = FL_READY;
+
+ // since FlashROM's area is USER domain, we need not to use copy_to_user()
+ memcpy(buf, (void *)addr, len);
+ *retlen = len;
+
+ if (chip->state == FL_ERASE_SUSPENDED ||
+ chip->state == FL_WRITE_SUSPENDED) {
+ printk("Who in hell suspended the pending operation? I didn't write that code yet!\n");
+ /* Restart it and set the state accordingly */
+ }
+
+ wake_up(&chip->wq);
+ spin_unlock_bh(chip->mutex);
+
+ return 0;
+}
+
+static int schm100_erase_oneblock(unsigned long addr)
+{
+ unsigned long timeo = jiffies + HZ;
+ DECLARE_WAITQUEUE(wait, current);
+ int ret, z;
+
+ ret = schm100_flash_wait(addr, &wait, &timeo, "erase");
+ if (ret != 0) return ret;
+
+ __IOW(addr) = FLASH_ERASE;
+ __IOW(addr) = FLASH_ERASE_CONFIRM;
+
+ chip->state = FL_ERASING;
+ timeo = jiffies + (HZ*2);
+
+ spin_unlock_bh(chip->mutex);
+ schedule_timeout(HZ);
+ spin_lock_bh(chip->mutex);
+
+ ret = schm100_flash_wait2(addr, &wait, &timeo, FL_ERASING, &z);
+ if (ret != 0) return ret;
+
+ /* Done and happy. */
+ chip->state = FL_STATUS;
+ wake_up(&chip->wq);
+ spin_unlock_bh(chip->mutex);
+
+ return 0;
+}
+
+static int schm100_mtd_erase (struct mtd_info *mtd, struct erase_info *instr)
+{
+ unsigned long adr, len;
+ int ret = 0;
+
+ if (instr->addr & (mtd->erasesize - 1))
+ return -EINVAL;
+
+ if (instr->len & (mtd->erasesize - 1))
+ return -EINVAL;
+
+ if ((instr->len + instr->addr) > mtd->size)
+ return -EINVAL;
+
+ ENABLE_VPP;
+
+ adr = instr->addr + (unsigned long)mtd->priv;
+ len = instr->len;
+
+ while(len) {
+ ret = schm100_erase_oneblock(adr);
+
+ if (ret) return ret;
+
+ adr += mtd->erasesize;
+ len -= mtd->erasesize;
+ }
+
+ if (instr->callback)
+ instr->callback(instr);
+
+ DISABLE_VPP;
+ return 0;
+}
+
+static int schm100_write_32(unsigned long addr, __u32 datum)
+{
+ unsigned long timeo = jiffies + HZ;
+ DECLARE_WAITQUEUE(wait, current);
+ int ret, z;
+
+#ifdef CONFIG_DEBUG_SCHM100_MTD
+ printk("[%s:%d] addr=%lx, datum=%lx\n", __FILE__, __LINE__, addr, datum);
+#endif
+ ret = schm100_flash_wait(addr, &wait, &timeo, "write");
+ if (ret != 0) return ret;
+
+ addr &= 0xFFFFFFFC;
+
+ __IOW(addr) = FLASH_WRITE;
+ __IOW(addr) = datum;
+
+ chip->state = FL_WRITING;
+ timeo = jiffies + (HZ/2);
+
+ spin_unlock_bh(chip->mutex);
+ udelay(chip->word_write_time);
+ spin_lock_bh(chip->mutex);
+
+ ret = schm100_flash_wait2(addr, &wait, &timeo, FL_WRITING, &z);
+ if (ret != 0) return ret;
+ if (!z) {
+ chip->word_write_time--;
+ if (!chip->word_write_time)
+ chip->word_write_time++;
+ }
+ if (z > 1)
+ chip->word_write_time++;
+
+ /* Done and happy. */
+ chip->state = FL_STATUS;
+ wake_up(&chip->wq);
+ spin_unlock_bh(chip->mutex);
+
+ //printk("write ret OK at %lx\n", adr);
+ return 0;
+}
+
+static int schm100_mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)
+{
+ int ret = 0;
+ __u32 tmp;
+ unsigned long addr;
+
+ *retlen = 0;
+ addr = to + (unsigned long)mtd->priv;
+
+ if (len < 1) return -EINVAL;
+ ENABLE_VPP;
+
+#if 0
+ /* If it's not word-aligned, do the first byte write */
+ tmp = 4 - addr & 0x03;
+ switch (tmp) {
+ case 0x01:
+ ret = schm100_write_32(addr, 0xFFFFFF | (*buf << 24));
+ break;
+ case 0x02:
+ ret = schm100_write_32(addr, 0xFFFF | ((*(__u16 *) tmp) << 16));
+ break;
+ case 0x03: tmp = 0xFF | (*buf << 24);
+ buf++; tmp |= (*buf << 16);
+ buf++; tmp |= (*buf << 8);
+ ret = schm100_write_32(addr, tmp);
+ break;
+ }
+ if (ret) return ret;
+
+ tmp = addr & 0x03;
+ buf++;
+ (*retlen) += tmp;
+ len -= tmp;
+ addr += tmp;
+#endif
+
+ while(len > 3) {
+ ret = schm100_write_32(addr, *(__u32 *)buf);
+ if (ret) return ret;
+
+ addr += 4;
+ buf += 4;
+ (*retlen) += 4;
+ len -= 4;
+ }
+
+#if 0
+ /* Final byte to write */
+ switch (len) {
+ case 0x01:
+ ret = schm100_write_32(addr, 0xFFFFFF00 | (*buf));
+ if (ret) return ret;
+ break;
+ case 0x02: tmp = 0xFFFF0000 | (*buf);
+ buf++; tmp |= (*buf << 8);
+ ret = schm100_write_32(addr, tmp);
+ if (ret) return ret;
+ break;
+ case 0x03: tmp = 0xFF000000 | (*buf);
+ buf++; tmp |= (*buf << 8);
+ buf++; tmp |= (*buf << 16);
+ ret = schm100_write_32(addr, tmp);
+ if (ret) return ret;
+ break;
+ }
+ (*retlen) += len;
+#endif
+
+ DISABLE_VPP;
+ return 0;
+}
+
+static void schm100_mtd_sync (struct mtd_info *mtd)
+{
+ DECLARE_WAITQUEUE(wait, current);
+
+ retry:
+ spin_lock_bh(chip->mutex);
+
+ switch(chip->state) {
+ case FL_READY:
+ case FL_STATUS:
+ case FL_CFI_QUERY:
+ case FL_JEDEC_QUERY:
+ chip->oldstate = chip->state;
+ chip->state = FL_SYNCING;
+ /* No need to wake_up() on this state change -
+ * as the whole point is that nobody can do anything
+ * with the chip now anyway.
+ */
+ spin_unlock_bh(chip->mutex);
+ break;
+
+ default:
+ /* Not an idle state */
+ add_wait_queue(&chip->wq, &wait);
+
+ spin_unlock_bh(chip->mutex);
+ schedule();
+
+ goto retry;
+ }
+
+ /* Unlock the chips again */
+ spin_lock_bh(chip->mutex);
+
+ if (chip->state == FL_SYNCING) {
+ chip->state = chip->oldstate;
+ wake_up(&chip->wq);
+ }
+ spin_unlock_bh(chip->mutex);
+}
+
+static int schm100_mtd_suspend (struct mtd_info *mtd)
+{
+ int ret = 0;
+
+ spin_lock_bh(chip->mutex);
+
+ switch(chip->state) {
+ case FL_READY:
+ case FL_STATUS:
+ case FL_CFI_QUERY:
+ case FL_JEDEC_QUERY:
+ chip->oldstate = chip->state;
+ chip->state = FL_PM_SUSPENDED;
+ /* No need to wake_up() on this state change -
+ * as the whole point is that nobody can do anything
+ * with the chip now anyway.
+ */
+ spin_unlock_bh(chip->mutex);
+ break;
+
+ default:
+ ret = -EAGAIN;
+ break;
+ }
+
+ /* Unlock the chips again */
+ spin_lock_bh(chip->mutex);
+
+ if (chip->state == FL_PM_SUSPENDED) {
+ chip->state = chip->oldstate;
+ wake_up(&chip->wq);
+ }
+ spin_unlock_bh(chip->mutex);
+
+ return ret;
+}
+
+static void schm100_mtd_resume (struct mtd_info *mtd)
+{
+ spin_lock_bh(chip->mutex);
+
+ if (chip->state == FL_PM_SUSPENDED) {
+ chip->state = chip->oldstate;
+ wake_up(&chip->wq);
+ }
+ else
+ printk("Argh. Chip not in PM_SUSPENDED state upon resume()\n");
+
+ spin_unlock_bh(chip->mutex);
+}
+
+#define BBFL_BOOT_BLOCK_SIZE 0x004000
+#define BBFL_BLOCK_SIZE 0x020000
+#ifdef CONFIG_SCHM100_MTD_4BLOCK
+static struct mtd_info my_mtds[4] = {
+#else
+static struct mtd_info my_mtds[3] = {
+#endif
+ /* MonitorCode, BootBlock, boot/kernel, fs */
+#ifdef CONFIG_SCHM100_MTD_4BLOCK
+ {
+ type: MTD_NORFLASH,
+ flags: MTD_CAP_NORFLASH,
+ size: FLASH_SIZE_1,
+ erasesize: BBFL_BOOT_BLOCK_SIZE,
+ name: "Monitor Code Area",
+ module: THIS_MODULE,
+ erase: NULL,
+ read: schm100_mtd_read,
+ write: NULL,
+ suspend: NULL,
+ resume: NULL,
+ sync: NULL,
+ },
+#endif
+ {
+ type: MTD_NORFLASH,
+ flags: MTD_CAP_NORFLASH,
+ size: FLASH_SIZE_2,
+ erasesize: BBFL_BOOT_BLOCK_SIZE,
+ name: "Boot Block",
+ module: THIS_MODULE,
+ erase: schm100_mtd_erase,
+ read: schm100_mtd_read,
+ write: schm100_mtd_write,
+ suspend: schm100_mtd_suspend,
+ resume: schm100_mtd_resume,
+ sync: schm100_mtd_sync,
+ },
+ {
+ type: MTD_NORFLASH,
+ flags: MTD_CAP_NORFLASH,
+ size: FLASH_SIZE_3,
+ erasesize: BBFL_BLOCK_SIZE,
+ name: "boot/Kernel",
+ module: THIS_MODULE,
+ erase: schm100_mtd_erase,
+ read: schm100_mtd_read,
+ write: schm100_mtd_write,
+ suspend: schm100_mtd_suspend,
+ resume: schm100_mtd_resume,
+ sync: schm100_mtd_sync,
+ },
+ {
+ type: MTD_NORFLASH,
+ flags: MTD_CAP_NORFLASH | MTD_XIP,
+ size: FLASH_SIZE_4,
+ erasesize: BBFL_BLOCK_SIZE,
+ name: "FileSystem",
+ module: THIS_MODULE,
+ erase: schm100_mtd_erase,
+ read: schm100_mtd_read,
+ write: schm100_mtd_write,
+ suspend: schm100_mtd_suspend,
+ resume: schm100_mtd_resume,
+ sync: schm100_mtd_sync,
+ }
+};
+
+#if LINUX_VERSION_CODE < 0x20300
+#ifdef MODULE
+#define init_schm100_mtd init_module
+#define cleanup_schm100_mtd cleanup_module
+
+static void __exit cleanup_schm100_mtd(void)
+{
+ int i;
+
+#ifdef CONFIG_SCHM100_MTD_4BLOCK
+ del_mtd_device(&my_mtds[2]);
+ del_mtd_device(&my_mtds[1]);
+ del_mtd_device(&my_mtds[0]);
+ del_mtd_device(&my_mtds[3]);
+ for(i=0; i<4; i++)
+ iounmap((void *)my_mtds[i].priv);
+#else
+ del_mtd_device(&my_mtds[1]);
+ del_mtd_device(&my_mtds[0]);
+ del_mtd_device(&my_mtds[2]);
+ for(i=0; i<3; i++)
+ iounmap((void *)my_mtds[i].priv);
+#endif
+ kfree(chip);
+}
+#endif
+#endif
+
+static int get_flash_id(void)
+{
+ volatile unsigned int c1, c2;
+
+ /*
+ * try to get flash chip ID
+ */
+ *(unsigned long *) (FLASH_STATUS) = FLASH_READ_ID;
+ udelay(15);
+ c1 = *(unsigned int *) FLASH_BASE;
+ c2 = *(unsigned int *) (FLASH_BASE + 4);
+
+ /*
+ * set it back to read mode
+ */
+ *(unsigned long *) (FLASH_STATUS) = FLASH_READ_ARRAY;
+
+ return c2;
+}
+
+#define KFLASH_ID 0x88918891 // Intel 28F160B3 x 2
+int __init init_schm100_mtd(void)
+{
+ int id;
+
+ id = get_flash_id();
+ if (id != KFLASH_ID) {
+ printk("Flash: incorrect ID 0x%04X.\n", id);
+ return -ENXIO;
+ }
+ printk("Flash: device ID 0x%04X, size 4Mbyte.\n", id);
+
+#ifdef CONFIG_SCHM100_MTD_4BLOCK
+ my_mtds[0].priv = (void *)__ioremap(FLASH_START_1, FLASH_SIZE_1, PTE_AP_READ);
+ my_mtds[1].priv = (void *)__ioremap(FLASH_START_2, FLASH_SIZE_2, PTE_AP_READ);
+ my_mtds[2].priv = (void *)__ioremap(FLASH_START_3, FLASH_SIZE_3, PTE_AP_READ);
+ my_mtds[3].priv = (void *)__ioremap(FLASH_START_4, FLASH_SIZE_4, PTE_AP_READ);
+#else
+ my_mtds[0].priv = (void *)__ioremap(FLASH_START_2, FLASH_SIZE_2, PTE_AP_READ);
+ my_mtds[1].priv = (void *)__ioremap(FLASH_START_3, FLASH_SIZE_3, PTE_AP_READ);
+ my_mtds[2].priv = (void *)__ioremap(FLASH_START_4, FLASH_SIZE_4, PTE_AP_READ);
+#endif
+#ifdef CONFIG_DEBUG_SCHM100_MTD
+ printk("[%s:%d] mtd[0]=%lx,size=%lx,priv=%lx\n", __FILE__, __LINE__, &my_mtds[0], (unsigned long)my_mtds[0].size, (unsigned long)my_mtds[0].priv);
+ printk("[%s:%d] mtd[1]=%lx,size=%lx,priv=%lx\n", __FILE__, __LINE__, &my_mtds[1], (unsigned long)my_mtds[1].size, (unsigned long)my_mtds[1].priv);
+ printk("[%s:%d] mtd[2]=%lx,size=%lx,priv=%lx\n", __FILE__, __LINE__, &my_mtds[2], (unsigned long)my_mtds[2].size, (unsigned long)my_mtds[2].priv);
+#ifdef CONFIG_SCHM100_MTD_4BLOCK
+ printk("[%s:%d] mtd[3]=%lx,size=%lx,priv=%lx\n", __FILE__, __LINE__, &my_mtds[3], (unsigned long)my_mtds[3].size, (unsigned long)my_mtds[3].priv);
+#endif
+#endif
+
+ chip = (struct flchip *)kmalloc(sizeof(struct flchip), GFP_KERNEL);
+ memset(chip, 0, sizeof(struct flchip));
+ init_waitqueue_head(&chip->wq);
+ spin_lock_init(&chip->_spinlock);
+ chip->start = (unsigned long)my_mtds[0].priv;
+ chip->state = FL_READY;
+ chip->mutex = &chip->_spinlock;
+
+ // mymtd = do_cfi_probe(&schm100_map);
+#ifdef CONFIG_SCHM100_MTD_4BLOCK
+ add_mtd_device(&my_mtds[3]);
+ add_mtd_device(&my_mtds[0]);
+ add_mtd_device(&my_mtds[1]);
+ add_mtd_device(&my_mtds[2]);
+#else
+ add_mtd_device(&my_mtds[2]);
+ add_mtd_device(&my_mtds[0]);
+ add_mtd_device(&my_mtds[1]);
+#endif
+ DISABLE_VPP;
+
+ return 0;
+}
+
diff -ruN mtd/kernel/schm100.h linux/drivers/mtd/schm100.h
--- mtd/kernel/schm100.h Thu Jan 1 09:00:00 1970
+++ linux/drivers/mtd/schm100.h Mon Aug 7 12:33:35 2000
@@ -0,0 +1,69 @@
+/*
+ * $Id: schm100.h,v 1.1 2000/08/07 02:37:14 tolkien Exp $
+ *
+ * Intel 3 volt Advanced Boot Block Flash Memory Device
+ * based in drivers/mtd/nora.c, drivers/mtd/cfi_cmd_0001.c
+ *
+ * Author:
+ * Yong-iL Joh <tolkien at mizi.com>
+ * Copyright 2000 Mizi Research
+ *
+ * License:
+ * As part of this driver was derrived from the slram.c driver it falls
+ * under the same license, which is GNU General Public License v2
+ *
+ */
+
+/* Flash Device Operation */
+#define FLASH_READ_ARRAY 0x00FF00FF
+#define FLASH_WRITE 0x00400040
+#define FLASH_ERASE 0x00200020
+#define FLASH_ERASE_CONFIRM 0x00D000D0
+#define FLASH_RESUME 0x00D000D0
+#define FLASH_SUSPEND 0x00B000B0
+#define FLASH_READ_STATUS 0x00700070
+#define FLASH_CLEAR_STATUS 0x00500050
+#define FLASH_READ_ID 0x00900090
+
+/* if 6 bit is set in DATA port A, Vpp pin's status is changed (High),
+ so FlashROM is read-only */
+#define VPP_MASK 0x40
+#define VPP_CLEAR_MASK 0xBF
+#define ENABLE_VPP { IO_PADDR |= 0x40; IO_PADR &= VPP_CLEAR_MASK; }
+#define DISABLE_VPP IO_PADR |= VPP_MASK
+#define FLASH_STATUS FLASH_BASE + 0x4000
+#define __IOW(x) (*(volatile __u32 *) (x))
+
+/* Status Register Bit Definition */
+#define FLS_WRITE 0x00800080 /* 1: Ready 0: Busy */
+#define FLS_ERASE_SUSPEND 0x00400040 /* 1: Suspend 0: Erase-Complete */
+#define FLS_ERASE 0x00200020 /* 1: Error 0: Success */
+#define FLS_PROGRAM 0x00100010 /* 1: Error 0: Success */
+#define FLS_VPP 0x00080008 /* 1: Vpp Low 0: Vpp Ok */
+#define FLS_PROG_SUSPEND 0x00040004 /* 1: Suspend 0: Program-Complete */
+#define FLS_LOCK 0x00020002 /* 1: Locked 0: no-Lock */
+
+/* Flash Map info. */
+#ifndef FLASH_ADDRESS_DEFINED
+#define FLASH_ADDRESS_DEFINED
+# define FLASH_BASE 0x70000000 /* virtual */
+# ifdef CONFIG_BOOT_FLASH_SCHM100
+# define FLASH_START 0x00000000 /* physical */
+# else
+# define FLASH_START 0x70000000 /* physical */
+# endif
+# define FLASH_SIZE 0x00400000 /* size: 4M */
+
+ /* 32k, Monitor Code Area */
+# define FLASH_START_1 (FLASH_START)
+# define FLASH_SIZE_1 0x00008000
+ /* 128k - 32k, BootBlock */
+# define FLASH_START_2 (FLASH_START_1 + FLASH_SIZE_1)
+# define FLASH_SIZE_2 (0x00020000 - FLASH_SIZE_1)
+ /* 1M - 128k, boot/Kernel, NonBootBlock */
+# define FLASH_START_3 (FLASH_START_2 + FLASH_SIZE_2)
+# define FLASH_SIZE_3 (FLASH_START + 0x00100000 - FLASH_START_3)
+ /* 3M, fs Area, NBB */
+# define FLASH_START_4 (FLASH_START_3 + FLASH_SIZE_3)
+# define FLASH_SIZE_4 (FLASH_START + FLASH_SIZE - FLASH_START_4)
+#endif
More information about the linux-mtd
mailing list