MTD lowlevel driver for SCH-M100

Yong-iL Joh tolkien at mizi.com
Sun Oct 15 21:57:47 EDT 2000


On Mon, Aug 07, 2000 at 01:04:34PM +0900, Yong-iL Joh wrote:
> 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.

plus, there is some add for kernel XIP
(run kernel core in FlashROM without loading RAM)

-- 
Joh, Yong-iL
E-mail: tolkien at nownuri.net tolkien at mizi.com
-------------- next part --------------
diff --exclude=CVS -ruN mtd/kernel/Config.in linux/drivers/mtd/Config.in
--- mtd/kernel/Config.in	Sun Oct 15 01:04:07 2000
+++ linux/drivers/mtd/Config.in	Mon Oct 16 10:09:08 2000
@@ -12,6 +12,7 @@
 fi
 
 if [ "$CONFIG_MTD" != "n" ]; then
+   dep_tristate 'Flash chips on SCH-M100' CONFIG_MTD_SCHM100 $CONFIG_MTD
 comment 'Disk-On-Chip Device Drivers'
    dep_tristate '  M-Systems Disk-On-Chip 1000' CONFIG_MTD_DOC1000 $CONFIG_MTD
    dep_tristate '  M-Systems Disk-On-Chip 2000' CONFIG_MTD_DOC2000 $CONFIG_MTD
diff --exclude=CVS -ruN mtd/kernel/Makefile linux/drivers/mtd/Makefile
--- mtd/kernel/Makefile	Mon Oct 16 01:04:07 2000
+++ linux/drivers/mtd/Makefile	Mon Oct 16 10:09:08 2000
@@ -60,6 +60,11 @@
 obj-$(CONFIG_MTD_NAND)		+= nand.o
 obj-$(CONFIG_MTD_NAND_SPIA)	+= spia.o
 obj-$(CONFIG_MTD_NAND_ECC)	+= nand_ecc.o
+ifdef CONFIG_XIP_ROM
+obj-$(CONFIG_MTD_SCHM100)	+= schm100_xip.o
+else
+obj-$(CONFIG_MTD_SCHM100)	+= schm100.o
+endif
 
 # Chip drivers
 obj-$(CONFIG_MTD_JEDEC)		+= jedec.o
diff --exclude=CVS -ruN mtd/kernel/mtdcore.c linux/drivers/mtd/mtdcore.c
--- mtd/kernel/mtdcore.c	Fri Oct 13 01:04:07 2000
+++ linux/drivers/mtd/mtdcore.c	Fri Oct  6 14:54:22 2000
@@ -58,6 +58,9 @@
 #ifdef CONFIG_MTD_NORA
 extern int init_nora(void);
 #endif
+#ifdef CONFIG_MTD_SCHM100
+extern int init_schm100_mtd(void);
+#endif
 #ifdef CONFIG_MTD_SBC_MEDIAGX
 extern int init_sbc_mediagx(void);
 #endif
@@ -419,6 +422,9 @@
 #ifdef CONFIG_MTD_NORA
 	init_nora();
 #endif
+#ifdef CONFIG_MTD_SCHM100
+	init_schm100_mtd();
+#endif
 #ifdef CONFIG_MTD_SBC_MEDIAGX
 	init_sbc_mediagx();
 #endif
@@ -456,7 +462,6 @@
 {
 	int i;
 
-	printk(KERN_INFO "Initializing MTD Layer\n");
 	for (i=0; i<MAX_MTD_DEVICES; i++)
 		mtd_table[i]=NULL;
 
diff --exclude=CVS -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 Oct 16 10:46:44 2000
@@ -0,0 +1,758 @@
+/*
+ * $Id: schm100.c,v 1.24 2000/10/16 01:46:44 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.
+ *
+ */
+
+#define USE_2_BLOCK	1
+#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);
+
+int schm100_mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
+{
+    unsigned long status;
+    unsigned long timeo = jiffies + HZ, addr, cmd_addr;
+    DECLARE_WAITQUEUE(wait, current);
+    int suspendedstate = 0;
+
+    addr = from + (unsigned long)mtd->priv;
+    if (len > mtd->size - from)	len = mtd->size - from;
+    if (len < 1)	return -EINVAL;
+
+    cmd_addr = addr & 0xFFFFFFFC;
+ retry:
+    spin_lock_bh(chip->mutex);
+
+    /* Check that the chip's ready to talk to us.
+     * If it's in FL_ERASING state, suspend it and make it talk now.
+     */
+    switch (chip->state) {
+    case FL_ERASING:
+	__IOW(cmd_addr) = FLASH_SUSPEND;
+	chip->oldstate = FL_ERASING;
+	chip->state = FL_ERASE_SUSPENDING;
+	timeo = jiffies + HZ;
+
+	status = __IOW(cmd_addr);
+	while (((status = __IOW(cmd_addr)) & FLS_READY) == 0) {
+	    if (time_after(jiffies, timeo)) {
+		__IOW(cmd_addr) = FLASH_RESUME;
+		chip->state = FL_ERASING;
+		spin_unlock_bh(chip->mutex);
+		printk("Chip not ready after erase suspended\n");
+		return -EIO;
+	    }
+	    spin_unlock_bh(chip->mutex);
+	    udelay(1);
+	    spin_lock_bh(chip->mutex);
+	}
+	chip->state = FL_ERASE_SUSPENDED;
+	/* Remember the status so we know whether to restart
+	   the erase later */
+	suspendedstate = status;
+	break;
+#if 0
+    case FL_WRITING:
+	/* Not quite yet */
+#endif
+    case FL_CFI_QUERY:
+    case FL_JEDEC_QUERY:
+    case FL_READY:
+	__IOW(cmd_addr) = FLASH_READ_STATUS;
+	chip->state = FL_STATUS;
+
+    case FL_STATUS:
+	status = __IOW(cmd_addr);
+
+	if (!(status & FLS_READY)) {
+	    static int z=0;
+	    /* Urgh. Chip not yet ready to talk to us. */
+	    if (time_after(jiffies, timeo)) {
+		spin_unlock_bh(chip->mutex);
+		printk("waiting for chip to be ready timed out in read");
+		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 read. looping\n");
+
+	    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);
+
+	spin_unlock_bh(chip->mutex);
+
+	schedule();
+	remove_wait_queue(&chip->wq, &wait);
+
+	timeo = jiffies + HZ;
+
+	goto retry;
+    }
+
+    __IOW(cmd_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 (suspendedstate) {
+	chip->state = chip->oldstate;
+	/* Resume if it hadn't already completed. */
+	if (suspendedstate & FLS_ERASE_SUSPEND) 
+	    __IOW(cmd_addr) = FLASH_RESUME;
+    }
+
+    wake_up(&chip->wq);
+    spin_unlock_bh(chip->mutex);
+
+    return 0;
+}
+
+int schm100_flash_wait(unsigned long addr, struct wait_queue *wait_p,
+				     unsigned long *timeo_p, const char *str) {
+  unsigned long status;
+
+  addr &= 0xFFFFFFFC;
+
+ 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) {
+  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_READY)) {
+	  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 0
+    if(signal_pending(current))
+      return -EINTR;
+#endif
+    *timeo_p = jiffies + HZ;
+
+    goto retry;
+  }
+
+  return 0;
+}
+
+int schm100_flash_wait2(unsigned long addr, struct wait_queue *wait_p, \
+				     unsigned long *timeo_p, flstate_t fls, int *z_p) {
+  unsigned long status, condition;
+  char *str, *str2;
+
+  addr &= 0xFFFFFFFC;
+  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_READY ) ) {
+
+    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 0
+      if (signal_pending(current))
+	return -EINTR;
+#endif
+      *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;
+  }	// while
+
+  if (status & condition) {
+      __IOW(addr) = FLASH_CLEAR_STATUS;
+      return status & condition;
+  }
+  return 0;
+}
+
+int schm100_erase_oneblock(unsigned long addr)
+{
+  unsigned long timeo = jiffies + HZ;
+  DECLARE_WAITQUEUE(wait, current);
+  int ret, z;
+
+  addr &= 0xFFFFFFFC;
+  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. */
+  __IOW(addr) = FLASH_READ_ARRAY;
+  chip->state = FL_READY;
+
+  wake_up(&chip->wq);
+  spin_unlock_bh(chip->mutex);
+
+  return 0;
+}
+
+int schm100_write_32(unsigned long addr, unsigned long datum)
+{
+  unsigned long timeo = jiffies + HZ;
+  DECLARE_WAITQUEUE(wait, current);
+  int ret, z;
+
+  DEBUG(MTD_DEBUG_LEVEL3, "[%s:%d] addr=%lx, datum=%lx\n", __FILE__, __LINE__, addr, datum);
+  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. */
+  __IOW(addr) = FLASH_READ_ARRAY;
+  chip->state = FL_READY;
+
+  wake_up(&chip->wq);
+  spin_unlock_bh(chip->mutex);
+
+  return 0;
+}
+
+static int schm100_mtd_erase (struct mtd_info *mtd, struct erase_info *instr)
+{
+  int ret = 0;
+  unsigned long adr, len;
+
+  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_mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)
+{
+  int ret = 0;
+  unsigned long tmp, addr;
+#if 0	// hacked by tolkien, memory dump. :)
+  int i,j,k;
+  u_char *str, *chr;
+#endif
+
+  *retlen = 0;
+  addr = to + (unsigned long)mtd->priv;
+
+#if 0	// hacked by tolkien, memory dump. :)
+#define	ONE_LINE	16
+  str = chr = buf;
+  printk("\n WRITE");
+  printk("\n[0x%08lx]:", addr);
+  for(i=0, k=0; i < len; i++, str++) {
+      if ((i != 0) && ((i % ONE_LINE) == 0)) {
+	  printk("\t");
+	  for(j=0; j < ONE_LINE; j++, chr++) {
+	      if ((*chr >= 0x20) && (*chr <= 0x7E)) {
+		  printk("%c", *chr);
+	      } else {
+		  printk(".");
+	      }
+	  }
+	  printk("\n[0x%08lx]:", addr + i);
+	  k += ONE_LINE;
+      }
+      printk("%02x ", *str);
+  }
+  printk("\t");
+  for(j=0; j < (i - k); j++, chr++) {
+      if ((*chr >= 0x20) && (*chr <= 0x7E)) {
+	  printk("%c", *chr);
+      } else {
+	  printk(".");
+      }
+  }
+  printk("\n");
+#endif
+
+  if (len < 1) return -EINVAL;
+  ENABLE_VPP;
+
+  /* If it's not word-aligned, do the first byte write */
+  tmp = addr & 0x03;
+  if (tmp) {
+      switch (tmp) {
+      case 0x01: tmp = 0xFF | ((*buf) << 8) | ((*(buf + 1)) << 16) | ((*(buf + 2)) << 24);
+	  break;
+      case 0x02: tmp = 0xFFFF | ((*buf) << 16) | ((*(buf + 1)) << 24);
+	  break;
+      case 0x03: tmp = 0xFFFFFF | ((*buf) << 24);
+	  break;
+      }
+      ret = schm100_write_32(addr, tmp);
+      if (ret)	return ret;
+
+      tmp = 4 - (addr & 0x03);
+      buf += tmp;
+      (*retlen) += tmp;
+      len -= tmp;
+      addr += tmp;
+  }
+
+  while(len > 3) {
+    ret = schm100_write_32(addr, *(unsigned long *)buf);
+    if (ret)	return ret;
+
+    addr += 4;
+    buf += 4;
+    (*retlen) += 4;
+    len -= 4;
+  }
+
+  /* Final byte to write */
+  if (len > 0) {
+      switch (len) {
+      case 0x01: tmp = 0xFFFFFF00 | (*buf);
+	  break;
+      case 0x02: tmp = 0xFFFF0000 | (*buf) | ((*(buf + 1)) << 8);
+	  break;
+      case 0x03: tmp = 0xFF000000 | (*buf) | ((*(buf + 1)) << 8) | ((*(buf + 2)) << 16);
+	  break;
+      }
+      ret = schm100_write_32(addr, tmp);
+      if (ret)	return ret;
+      (*retlen) += len;
+  }
+
+  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.
+     */
+  case FL_SYNCING:
+    spin_unlock_bh(chip->mutex);
+    break;
+
+  default:
+    /* Not an idle state */
+    add_wait_queue(&chip->wq, &wait);
+
+    spin_unlock_bh(chip->mutex);
+    schedule();
+    remove_wait_queue(&chip->wq, &wait);
+
+    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.
+     */
+  case FL_PM_SUSPENDED:
+    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 USE_2_BLOCK
+#  define SCHM100_MTD_BLOCK_NO	1
+#else
+#  define SCHM100_MTD_BLOCK_NO	2
+#endif
+
+static struct mtd_info my_mtds[SCHM100_MTD_BLOCK_NO] = {
+#ifndef USE_2_BLOCK
+  {
+    type: MTD_NORFLASH,
+    flags: MTD_CAP_NORFLASH,
+    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,
+  }
+#else
+  {
+    type: MTD_NORFLASH,
+    flags: MTD_CAP_NORFLASH,
+    size: FLASH_SIZE_4 - XIP_SIZE,
+    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,
+  },
+  {
+    type: MTD_NORFLASH,
+    flags: MTD_CAP_NORFLASH | MTD_XIP,
+    size: XIP_SIZE,
+    erasesize: BBFL_BLOCK_SIZE,
+    name: "ROM disk",
+    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,
+  }
+#endif
+};
+
+#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)
+{
+    del_mtd_device(&my_mtds[0]);
+    iounmap((void *)my_mtds[0].priv);
+#ifndef USE_2_BLOCK
+    del_mtd_device(&my_mtds[1]);
+    iounmap((void *)my_mtds[1].priv);
+#endif
+    kfree(chip);
+}
+#endif
+#endif
+
+int get_flash_id(void)
+{
+    volatile unsigned int c1, c2;
+
+    /*
+     * try to get flash chip ID
+     */
+    __IOW(FLASH_BASE) = FLASH_READ_ID;
+    udelay(15);
+    c1 = __IOW(FLASH_BASE);
+    c2 = __IOW(FLASH_BASE + 4);
+
+    /*
+     * set it back to read mode
+     */
+    __IOW(FLASH_BASE) = FLASH_READ_ARRAY;
+
+    return c2;
+}
+
+#define	KFLASH_ID	0x88918891	// Intel 28F160B3 x 2
+int __init init_schm100_mtd(void)
+{
+  int id;
+  unsigned long tmp;
+
+  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);
+
+  /* set 32bit wide, Memory Configuration Register 1 - NCS0 */
+  tmp = IO_SYSFLG1 & BOOTBIT;
+  switch (tmp) {
+  case BOOTBIT_32:
+      IO_MEMCFG1 |= CS_BW_BUS32_E0;
+      break;
+  case BOOTBIT_8:
+      IO_MEMCFG1 |= CS_BW_BUS32_E1;
+      break;
+  case BOOTBIT_16:
+      IO_MEMCFG1 |= CS_BW_BUS32_E2;
+      break;
+  }
+
+#ifndef USE_2_BLOCK
+  my_mtds[0].priv = (void *)__ioremap(FLASH_START_4, FLASH_SIZE_4, PTE_AP_READ);
+#else
+  my_mtds[0].priv = (void *)__ioremap(FLASH_START_4, FLASH_SIZE_4 - XIP_SIZE, PTE_AP_READ);
+  my_mtds[1].priv = (void *)__ioremap(FLASH_START_4 + FLASH_SIZE_4 - XIP_SIZE, XIP_SIZE, PTE_AP_READ);
+#endif
+  DEBUG(MTD_DEBUG_LEVEL1, "[%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);
+#ifdef USE_2_BLOCK
+  DEBUG(MTD_DEBUG_LEVEL1, "[%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);
+#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;
+#if 0	// hacked by tolkien
+  chip->state = FL_STATUS;
+#else
+  __IOW(chip->start) = FLASH_READ_ARRAY;
+  chip->state = FL_READY;
+#endif
+  chip->mutex = &chip->_spinlock;
+
+  add_mtd_device(&my_mtds[0]);
+#ifdef USE_2_BLOCK
+  add_mtd_device(&my_mtds[1]);
+#endif
+  DISABLE_VPP;
+
+  return 0;
+}
diff --exclude=CVS -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 Oct 16 10:46:44 2000
@@ -0,0 +1,76 @@
+/*
+ * $Id: schm100.h,v 1.6 2000/10/16 01:46:44 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 __IOW(x)	(*(volatile unsigned long *) (x))
+
+/* Status Register Bit Definition */
+#define FLS_READY		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 */
+
+#define	__move2RAM	__attribute__ ((__section__ (".text.xip_ram")))
+
+#if 0	// it's a code in include/asm-arm/arch-clps7111/hardware.h
+#define FLASH_BASE		0x70000000
+
+#ifdef CONFIG_BOOT_FLASH_SCHM100
+#define FLASH_START		0x00000000
+#else
+#define FLASH_START		0x70000000
+#endif
+						/* size */
+#define FLASH_SIZE		0x00400000	/*  4M */
+
+/* Flash Map info. */
+				/* 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)
+
+#ifdef USE_2_BLOCK		/* reserved area for appl. XIP */
+# define XIP_SIZE		0x00100000
+# define XIP_BASE		FLASH_START + FLASH_SIZE - XIP_SIZE
+#endif
+#endif	// #if 0
diff --exclude=CVS -ruN mtd/kernel/schm100_xip.c linux/drivers/mtd/schm100_xip.c
--- mtd/kernel/schm100_xip.c	Thu Jan  1 09:00:00 1970
+++ linux/drivers/mtd/schm100_xip.c	Mon Oct 16 10:50:00 2000
@@ -0,0 +1,570 @@
+/*
+ * $Id: schm100_xip.c,v 1.3 2000/10/16 01:50:00 tolkien Exp $
+ *
+ * Intel 3 volt Advanced Boot Block Flash Memory Device
+ * based in drivers/mtd/nora.c, drivers/mtd/cfi_cmd_0001.c
+ * when kernel XIP.
+ *
+ * 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.
+ *
+ */
+
+#define USE_2_BLOCK		1
+#define DO_NOT_PERMIT_INTERRUPT	1
+#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);
+#define	UDELAY_N	1000
+
+__move2RAM
+int schm100_mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
+{
+    unsigned long addr;
+
+    addr = from + (unsigned long)mtd->priv;
+    if (len > mtd->size - from)	len = mtd->size - from;
+    if (len < 1)	return -EINVAL;
+
+    spin_lock_bh(chip->mutex);
+    __IOW(addr & 0xFFFFFFFC) = FLASH_READ_ARRAY;
+    spin_unlock_bh(chip->mutex);
+    // since FlashROM's area is USER domain, we need not to use copy_to_user()
+    memcpy(buf, (void *)addr, len);
+    *retlen = len;
+    return 0;
+}
+
+__move2RAM
+int schm100_erase_oneblock(unsigned long addr) {
+    int ret;
+    unsigned long status;
+
+    addr &= 0xFFFFFFFC;
+    __IOW(addr) = FLASH_CLEAR_STATUS;
+    __IOW(addr) = FLASH_ERASE;
+    __IOW(addr) = FLASH_ERASE_CONFIRM;
+    __IOW(addr) = FLASH_READ_STATUS;
+
+    while ((__IOW(addr) & FLS_READY) != FLS_READY) {}
+
+    status = __IOW(addr);
+    if ((status & FLS_VPP) != FLS_VPP) {
+	if ((status & (FLS_ERASE | FLS_PROGRAM)) != (FLS_ERASE | FLS_PROGRAM)) {
+	    if ((status & FLS_ERASE) != FLS_ERASE) {
+		if ((status & FLS_LOCK) != FLS_LOCK) {
+		    ret = 0;		// successful
+		} else {
+		    ret = -EWOULDBLOCK;	// access a locked block
+		}
+	    } else {
+		ret = -EIO;		// Error
+	    }
+	} else {
+	    ret = -EINVAL;		// Command Sequence Error
+	}
+    } else {
+	ret = -EIO;			// Vpp range Error
+    }
+    __IOW(addr) = FLASH_CLEAR_STATUS;
+    __IOW(addr) = FLASH_READ_ARRAY;
+
+    return ret;
+}
+
+__move2RAM
+int schm100_write_32(unsigned long addr, unsigned long datum) {
+    int ret;
+    unsigned long status;
+
+    addr &= 0xFFFFFFFC;
+    __IOW(addr) = FLASH_CLEAR_STATUS;
+    __IOW(addr) = FLASH_WRITE;
+    __IOW(addr) = datum;
+    __IOW(addr) = FLASH_READ_STATUS;
+
+    while ((__IOW(addr) & FLS_READY) != FLS_READY) {}
+
+    status = __IOW(addr);
+    if ((status & FLS_VPP) != FLS_VPP) {
+	if ((status & FLS_PROGRAM) != FLS_PROGRAM) {
+	    if ((status & FLS_LOCK) != FLS_LOCK) {
+		ret = 0;		// successful
+	    } else {
+		ret = -EWOULDBLOCK;	// access a locked block
+	    }
+	} else {
+	    ret = -EINVAL;		// Command Sequence Error
+	}
+    } else {
+	ret = -EIO;			// Vpp range Error
+    }
+    __IOW(addr) = FLASH_CLEAR_STATUS;
+    __IOW(addr) = FLASH_READ_ARRAY;
+
+    return ret;
+}
+
+static int schm100_mtd_erase (struct mtd_info *mtd, struct erase_info *instr)
+{
+  int ret = 0;
+  unsigned long adr, len;
+  unsigned long old_policy, old_rt_priority;
+#define RT_ERASE(addr)	{	\
+		spin_lock_irq(&runqueue_lock);	\
+		read_lock(&tasklist_lock);	\
+		old_policy = current->policy;	\
+		old_rt_priority = current->rt_priority;	\
+		current->policy = SCHED_OTHER;	\
+		current->rt_priority = 0;	\
+		current->need_resched = 1;	\
+		ret = schm100_erase_oneblock(addr);	\
+		current->policy = old_policy;	\
+		current->rt_priority = old_rt_priority;	\
+		current->need_resched = 1;	\
+		read_unlock(&tasklist_lock);	\
+		spin_unlock_irq(&runqueue_lock);	\
+		if (ret)	return ret;	\
+		}
+
+  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) {
+    RT_ERASE(adr);
+
+    adr += mtd->erasesize;
+    len -= mtd->erasesize;
+  }
+
+  if (instr->callback)
+    instr->callback(instr);
+
+  DISABLE_VPP;
+  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;
+  unsigned long tmp, addr;
+  unsigned long old_policy, old_rt_priority;
+#if 0	// hacked by tolkien, memory dump. :)
+  int i,j,k;
+  u_char *str, *chr;
+#endif
+
+#define RT_WRITE(addr, datum)	{	\
+		spin_lock_irq(&runqueue_lock);	\
+		read_lock(&tasklist_lock);	\
+		old_policy = current->policy;	\
+		old_rt_priority = current->rt_priority;	\
+		current->policy = SCHED_OTHER;	\
+		current->rt_priority = 0;	\
+		current->need_resched = 1;	\
+		ret = schm100_write_32((addr), (datum));	\
+		current->policy = old_policy;	\
+		current->rt_priority = old_rt_priority;	\
+		current->need_resched = 1;	\
+		read_unlock(&tasklist_lock);	\
+		spin_unlock_irq(&runqueue_lock);	\
+		if (ret)	return ret;	\
+		}
+ 
+  *retlen = 0;
+  addr = to + (unsigned long)mtd->priv;
+
+#if 0	// hacked by tolkien, memory dump. :)
+#define	ONE_LINE	16
+  str = chr = buf;
+  printk("\n WRITE");
+  printk("\n[0x%08lx]:", addr);
+  for(i=0, k=0; i < len; i++, str++) {
+      if ((i != 0) && ((i % ONE_LINE) == 0)) {
+	  printk("\t");
+	  for(j=0; j < ONE_LINE; j++, chr++) {
+	      if ((*chr >= 0x20) && (*chr <= 0x7E)) {
+		  printk("%c", *chr);
+	      } else {
+		  printk(".");
+	      }
+	  }
+	  printk("\n[0x%08lx]:", addr + i);
+	  k += ONE_LINE;
+      }
+      printk("%02x ", *str);
+  }
+  printk("\t");
+  for(j=0; j < (i - k); j++, chr++) {
+      if ((*chr >= 0x20) && (*chr <= 0x7E)) {
+	  printk("%c", *chr);
+      } else {
+	  printk(".");
+      }
+  }
+  printk("\n");
+#endif
+
+  if (len < 1) return -EINVAL;
+  ENABLE_VPP;
+
+  /* If it's not word-aligned, do the first byte write */
+  tmp = addr & 0x03;
+  if (tmp) {
+      switch (tmp) {
+      case 0x01: tmp = 0xFF | ((*buf) << 8) | ((*(buf + 1)) << 16) | ((*(buf + 2)) << 24);
+	  break;
+      case 0x02: tmp = 0xFFFF | ((*buf) << 16) | ((*(buf + 1)) << 24);
+	  break;
+      case 0x03: tmp = 0xFFFFFF | ((*buf) << 24);
+	  break;
+      }
+      RT_WRITE(addr, tmp);
+
+      tmp = 4 - (addr & 0x03);
+      buf += tmp;
+      (*retlen) += tmp;
+      len -= tmp;
+      addr += tmp;
+  }
+
+  while(len > 3) {
+    RT_WRITE(addr, *(unsigned long *)buf);
+
+    addr += 4;
+    buf += 4;
+    (*retlen) += 4;
+    len -= 4;
+  }
+
+  /* Final byte to write */
+  if (len > 0) {
+      switch (len) {
+      case 0x01: tmp = 0xFFFFFF00 | (*buf);
+	  break;
+      case 0x02: tmp = 0xFFFF0000 | (*buf) | ((*(buf + 1)) << 8);
+	  break;
+      case 0x03: tmp = 0xFF000000 | (*buf) | ((*(buf + 1)) << 8) | ((*(buf + 2)) << 16);
+	  break;
+      }
+      RT_WRITE(addr, tmp);
+      (*retlen) += len;
+  }
+
+  DISABLE_VPP;
+  return 0;
+}
+
+#ifndef DO_NOT_PERMIT_INTERRUPT
+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.
+     */
+  case FL_SYNCING:
+    spin_unlock_bh(chip->mutex);
+    break;
+
+  default:
+    /* Not an idle state */
+    add_wait_queue(&chip->wq, &wait);
+
+    spin_unlock_bh(chip->mutex);
+    schedule();
+    remove_wait_queue(&chip->wq, &wait);
+
+    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.
+     */
+  case FL_PM_SUSPENDED:
+    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);
+}
+#endif
+
+#define BBFL_BOOT_BLOCK_SIZE	0x004000
+#define BBFL_BLOCK_SIZE		0x020000
+#ifdef USE_2_BLOCK
+#  define SCHM100_MTD_BLOCK_NO	1
+#else
+#  define SCHM100_MTD_BLOCK_NO	2
+#endif
+
+static struct mtd_info my_mtds[SCHM100_MTD_BLOCK_NO] = {
+#ifndef USE_2_BLOCK
+  {
+    type: MTD_NORFLASH,
+    flags: MTD_CAP_NORFLASH,
+    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,
+  }
+#else
+  {
+    type: MTD_NORFLASH,
+    flags: MTD_CAP_NORFLASH,
+    size: FLASH_SIZE_4 - XIP_SIZE,
+    erasesize: BBFL_BLOCK_SIZE,
+    name: "FileSystem",
+    module: THIS_MODULE,
+    erase: schm100_mtd_erase,
+    read: schm100_mtd_read,
+    write: schm100_mtd_write,
+#ifndef DO_NOT_PERMIT_INTERRUPT
+    suspend: schm100_mtd_suspend,
+    resume: schm100_mtd_resume,
+    sync: schm100_mtd_sync,
+#else
+    suspend: NULL,
+    resume: NULL,
+    sync: NULL,
+#endif
+  },
+  {
+    type: MTD_NORFLASH,
+    flags: MTD_CAP_NORFLASH | MTD_XIP,
+    size: XIP_SIZE,
+    erasesize: BBFL_BLOCK_SIZE,
+    name: "ROM disk",
+    module: THIS_MODULE,
+    erase: schm100_mtd_erase,
+    read: schm100_mtd_read,
+    write: schm100_mtd_write,
+#ifndef DO_NOT_PERMIT_INTERRUPT
+    suspend: schm100_mtd_suspend,
+    resume: schm100_mtd_resume,
+    sync: schm100_mtd_sync,
+#else
+    suspend: NULL,
+    resume: NULL,
+    sync: NULL,
+#endif
+  }
+#endif
+};
+
+#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)
+{
+    del_mtd_device(&my_mtds[0]);
+    iounmap((void *)my_mtds[0].priv);
+#ifndef USE_2_BLOCK
+    del_mtd_device(&my_mtds[1]);
+    iounmap((void *)my_mtds[1].priv);
+#endif
+    kfree(chip);
+}
+#endif
+#endif
+
+__move2RAM
+int get_flash_id(void)
+{
+    volatile unsigned int c1, c2;
+    int i;
+
+    /*
+     * try to get flash chip ID
+     */
+    __IOW(FLASH_BASE) = FLASH_READ_ID;
+    for(i=0; i < 15 * UDELAY_N; i++) i = i;
+    c1 = __IOW(FLASH_BASE);
+    c2 = __IOW(FLASH_BASE + 4);
+
+    /*
+     * set it back to read mode
+     */
+    __IOW(FLASH_BASE) = FLASH_READ_ARRAY;
+
+    return c2;
+}
+
+#define	KFLASH_ID	0x88918891	// Intel 28F160B3 x 2
+int __init init_schm100_mtd(void)
+{
+  int id;
+  unsigned long tmp;
+
+  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);
+
+  /* set 32bit wide, Memory Configuration Register 1 - NCS0 */
+  tmp = IO_SYSFLG1 & BOOTBIT;
+  switch (tmp) {
+  case BOOTBIT_32:
+      IO_MEMCFG1 |= CS_BW_BUS32_E0;
+      break;
+  case BOOTBIT_8:
+      IO_MEMCFG1 |= CS_BW_BUS32_E1;
+      break;
+  case BOOTBIT_16:
+      IO_MEMCFG1 |= CS_BW_BUS32_E2;
+      break;
+  }
+
+#ifndef USE_2_BLOCK
+  my_mtds[0].priv = (void *)__ioremap(FLASH_START_4, FLASH_SIZE_4, PTE_AP_READ);
+#else
+  my_mtds[0].priv = (void *)__ioremap(FLASH_START_4, FLASH_SIZE_4 - XIP_SIZE, PTE_AP_READ);
+  my_mtds[1].priv = (void *)__ioremap(FLASH_START_4 + FLASH_SIZE_4 - XIP_SIZE, XIP_SIZE, PTE_AP_READ);
+#endif
+  DEBUG(MTD_DEBUG_LEVEL1, "[%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);
+#ifdef USE_2_BLOCK
+  DEBUG(MTD_DEBUG_LEVEL1, "[%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);
+#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;
+#if 0	// hacked by tolkien
+  chip->state = FL_STATUS;
+#else
+  __IOW(chip->start) = FLASH_READ_ARRAY;
+  chip->state = FL_READY;
+#endif
+  chip->mutex = &chip->_spinlock;
+
+  add_mtd_device(&my_mtds[0]);
+#ifdef USE_2_BLOCK
+  add_mtd_device(&my_mtds[1]);
+#endif
+  DISABLE_VPP;
+
+  return 0;
+}
+
+/*
+ | $Id: schm100_xip.c,v 1.3 2000/10/16 01:50:00 tolkien Exp $
+ |
+ | Local Variables:
+ | mode: c
+ | mode: font-lock
+ | version-control: t
+ | delete-old-versions: t
+ | End:
+ |
+ | -*- End-Of-File -*-
+ */


More information about the linux-mtd mailing list