Merge ../linux-2.6-watchdog-mm
[pandora-kernel.git] / drivers / mtd / nand / cs553x_nand.c
index bf25125..8296305 100644 (file)
@@ -11,7 +11,7 @@
  * published by the Free Software Foundation.
  *
  *  Overview:
- *   This is a device driver for the NAND flash controller found on 
+ *   This is a device driver for the NAND flash controller found on
  *   the AMD CS5535/CS5536 companion chipsets for the Geode processor.
  *
  */
 
 #define NR_CS553X_CONTROLLERS  4
 
+#define MSR_DIVIL_GLD_CAP      0x51400000      /* DIVIL capabilitiies */
+#define CAP_CS5535             0x2df000ULL
+#define CAP_CS5536             0x5df500ULL
+
 /* NAND Timing MSRs */
 #define MSR_NANDF_DATA         0x5140001b      /* NAND Flash Data Timing MSR */
 #define MSR_NANDF_CTL          0x5140001c      /* NAND Flash Control Timing */
@@ -131,33 +135,17 @@ static void cs553x_write_byte(struct mtd_info *mtd, u_char byte)
        writeb(byte, this->IO_ADDR_W + 0x801);
 }
 
-static void cs553x_hwcontrol(struct mtd_info *mtd, int cmd)
+static void cs553x_hwcontrol(struct mtd_info *mtd, int cmd,
+                            unsigned int ctrl)
 {
        struct nand_chip *this = mtd->priv;
        void __iomem *mmio_base = this->IO_ADDR_R;
-       unsigned char ctl;
-
-       switch (cmd) {
-       case NAND_CTL_SETCLE:
-               ctl = CS_NAND_CTL_CLE;
-               break;
-
-       case NAND_CTL_CLRCLE:
-       case NAND_CTL_CLRALE:
-       case NAND_CTL_SETNCE:
-               ctl = 0;
-               break;
-
-       case NAND_CTL_SETALE:
-               ctl = CS_NAND_CTL_ALE;
-               break;
-
-       default:
-       case NAND_CTL_CLRNCE:
-               ctl = CS_NAND_CTL_CE;
-               break;
+       if (ctrl & NAND_CTRL_CHANGE) {
+               unsigned char ctl = (ctrl & ~NAND_CTRL_CHANGE ) ^ 0x01;
+               writeb(ctl, mmio_base + MM_NAND_CTL);
        }
-       writeb(ctl, mmio_base + MM_NAND_CTL);
+       if (cmd != NAND_CMD_NONE)
+               cs553x_write_byte(mtd, cmd);
 }
 
 static int cs553x_device_ready(struct mtd_info *mtd)
@@ -233,20 +221,21 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr)
                goto out_mtd;
        }
 
-       this->hwcontrol = cs553x_hwcontrol;
+       this->cmd_ctrl = cs553x_hwcontrol;
        this->dev_ready = cs553x_device_ready;
        this->read_byte = cs553x_read_byte;
-       this->write_byte = cs553x_write_byte;
        this->read_buf = cs553x_read_buf;
        this->write_buf = cs553x_write_buf;
 
        this->chip_delay = 0;
 
-       this->eccmode = NAND_ECC_HW3_256;
-       this->enable_hwecc  = cs_enable_hwecc;
-       this->calculate_ecc = cs_calculate_ecc;
-       this->correct_data  = nand_correct_data;
-       
+       this->ecc.mode = NAND_ECC_HW;
+       this->ecc.size = 256;
+       this->ecc.bytes = 3;
+       this->ecc.hwctl  = cs_enable_hwecc;
+       this->ecc.calculate = cs_calculate_ecc;
+       this->ecc.correct  = nand_correct_data;
+
        /* Enable the following for a flash based bad block table */
        this->options = NAND_USE_FLASH_BBT | NAND_NO_AUTOINCR;
 
@@ -260,24 +249,47 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr)
        goto out;
 
 out_ior:
-       iounmap((void *)this->IO_ADDR_R);
+       iounmap(this->IO_ADDR_R);
 out_mtd:
        kfree(new_mtd);
 out:
        return err;
 }
 
+static int is_geode(void)
+{
+       /* These are the CPUs which will have a CS553[56] companion chip */
+       if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD &&
+           boot_cpu_data.x86 == 5 &&
+           boot_cpu_data.x86_model == 10)
+               return 1; /* Geode LX */
+
+       if ((boot_cpu_data.x86_vendor == X86_VENDOR_NSC ||
+            boot_cpu_data.x86_vendor == X86_VENDOR_CYRIX) &&
+           boot_cpu_data.x86 == 5 &&
+           boot_cpu_data.x86_model == 5)
+               return 1; /* Geode GX (née GX2) */
+
+       return 0;
+}
+
 static int __init cs553x_init(void)
 {
        int err = -ENXIO;
        int i;
        uint64_t val;
 
-       /* Check whether we actually have a CS5535 or CS5536 */
-       if (!pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA, NULL) &&
-           !pci_find_device(PCI_VENDOR_ID_NS,  PCI_DEVICE_ID_NS_CS5535_ISA, NULL))
+       /* If the CPU isn't a Geode GX or LX, abort */
+       if (!is_geode())
+               return -ENXIO;
+
+       /* If it doesn't have the CS553[56], abort */
+       rdmsrl(MSR_DIVIL_GLD_CAP, val);
+       val &= ~0xFFULL;
+       if (val != CAP_CS5535 && val != CAP_CS5536)
                return -ENXIO;
 
+       /* If it doesn't have the NAND controller enabled, abort */
        rdmsrl(MSR_DIVIL_BALL_OPTS, val);
        if (val & 1) {
                printk(KERN_INFO "CS553x NAND controller: Flash I/O not enabled in MSR_DIVIL_BALL_OPTS.\n");
@@ -291,7 +303,7 @@ static int __init cs553x_init(void)
                        err = cs553x_init_one(i, !!(val & FLSH_MEM_IO), val & 0xFFFFFFFF);
        }
 
-       /* Register all devices together here. This means we can easily hack it to 
+       /* Register all devices together here. This means we can easily hack it to
           do mtdconcat etc. if we want to. */
        for (i = 0; i < NR_CS553X_CONTROLLERS; i++) {
                if (cs553x_mtd[i]) {