diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-07-08 00:53:00 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-07-08 00:53:00 +0000 |
commit | b8553086288629b4efb77e97f5582e08bc50ad65 (patch) | |
tree | 0a19bd1c21e148f35c7a0f76baa4f7a056b966b0 /drivers/mtd/docprobe.c | |
parent | 75b6d92f2dd5112b02f4e78cf9f35f9825946ef0 (diff) |
Merge with 2.4.0-test3-pre4.
Diffstat (limited to 'drivers/mtd/docprobe.c')
-rw-r--r-- | drivers/mtd/docprobe.c | 269 |
1 files changed, 269 insertions, 0 deletions
diff --git a/drivers/mtd/docprobe.c b/drivers/mtd/docprobe.c new file mode 100644 index 000000000..b2c4380d3 --- /dev/null +++ b/drivers/mtd/docprobe.c @@ -0,0 +1,269 @@ + +/* Linux driver for Disk-On-Chip devices */ +/* Probe routines common to all DoC devices */ +/* (c) 1999 Machine Vision Holdings, Inc. */ +/* Author: David Woodhouse <dwmw2@mvhi.com> */ +/* $Id: docprobe.c,v 1.8 2000/06/26 20:40:53 dwmw2 Exp $ */ + + + +/* DOC_PASSIVE_PROBE: + In order to ensure that the BIOS checksum is correct at boot time, and + hence that the onboard BIOS extension gets executed, the DiskOnChip + goes into reset mode when it is read sequentially: all registers + return 0xff until the chip is woken up again by writing to the + DOCControl register. + + Unfortunately, this means that the probe for the DiskOnChip is unsafe, + because one of the first things it does is write to where it thinks + the DOCControl register should be - which may well be shared memory + for another device. I've had machines which lock up when this is + attempted. Hence the possibility to do a passive probe, which will fail + to detect a chip in reset mode, but is at least guaranteed not to lock + the machine. + + If you have this problem, uncomment the following line: +#define DOC_PASSIVE_PROBE +*/ + + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/kmod.h> +#include <asm/errno.h> +#include <asm/io.h> +#include <asm/uaccess.h> +#include <linux/miscdevice.h> +#include <linux/pci.h> +#include <linux/delay.h> +#include <linux/malloc.h> +#include <linux/sched.h> +#include <linux/init.h> +#include <linux/types.h> + +#include <linux/mtd/mtd.h> +#include <linux/mtd/nand.h> +#include <linux/mtd/doc2000.h> + +/* Where to look for the devices? */ + +#if defined (__alpha__) || defined(__i386__) +static unsigned long __initdata doc_locations[] = { + 0xc8000, 0xca000, 0xcc000, 0xce000, + 0xd0000, 0xd2000, 0xd4000, 0xd6000, + 0xd8000, 0xda000, 0xdc000, 0xde000, + 0xe0000, 0xe2000, 0xe4000, 0xe6000, + 0xe8000, 0xea000, 0xec000, 0xee000, 0 }; +#elif defined(__ppc__) +static unsigned long __initdata doc_locations[] = { + 0xe4000000, 0}; +#else +#warning Unknown architecture for DiskOnChip. No default probe locations defined +#endif + +#ifdef CONFIG_MTD_DOC2000 +extern void DoC2k_init(struct mtd_info *); +#endif +#ifdef CONFIG_MTD_DOC2001 +extern void DoCMil_init(struct mtd_info *); +#endif + +/* doccheck: Probe a given memory window to see if there's a DiskOnChip present */ + +static inline int __init doccheck(unsigned long potential, unsigned long physadr) +{ + unsigned long window=potential; + unsigned char tmp, ChipID; +#ifndef DOC_PASSIVE_PROBE + unsigned char tmp2; +#endif + + /* Routine copied from the Linux DOC driver */ + + /* Check for 0x55 0xAA signature at beginning of window */ + if (ReadDOC(window, Sig1) != 0x55 || ReadDOC(window, Sig2) != 0xaa) + return 0; + +#ifndef DOC_PASSIVE_PROBE + /* It's not possible to cleanly detect the DiskOnChip - the + * bootup procedure will put the device into reset mode, and + * it's not possible to talk to it without actually writing + * to the DOCControl register. So we store the current contents + * of the DOCControl register's location, in case we later decide + * that it's not a DiskOnChip, and want to put it back how we + * found it. + */ + tmp2 = ReadDOC(window, DOCControl); + + /* Reset the DiskOnChip ASIC */ + WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, + window, DOCControl); + WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, + window, DOCControl); + + /* Enable the DiskOnChip ASIC */ + WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, + window, DOCControl); + WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, + window, DOCControl); +#endif /* !DOC_PASSIVE_PROBE */ + + ChipID = ReadDOC(window, ChipID); + + switch (ChipID) { + case DOC_ChipID_Doc2k: + /* Check the TOGGLE bit in the ECC register */ + tmp = ReadDOC(window, 2k_ECCStatus) & DOC_TOGGLE_BIT; + if ((ReadDOC(window, 2k_ECCStatus) & DOC_TOGGLE_BIT) != tmp) + return ChipID; + break; + + case DOC_ChipID_DocMil: + /* Check the TOGGLE bit in the ECC register */ + tmp = ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT; + if ((ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT) != tmp) + return ChipID; + break; + + default: + printk(KERN_WARNING "Possible DiskOnChip with unknown ChipID %2.2X found at 0x%lx\n", + ChipID, physadr); + +#ifndef DOC_PASSIVE_PROBE + /* Put back the contents of the DOCControl register, in case it's not + * actually a DiskOnChip. + */ + WriteDOC(tmp2, window, DOCControl); +#endif + return 0; + } + + printk(KERN_WARNING "DiskOnChip failed TOGGLE test, dropping.\n"); + +#ifndef DOC_PASSIVE_PROBE + /* Put back the contents of the DOCControl register: it's not a DiskOnChip */ + WriteDOC(tmp2, window, DOCControl); +#endif + return 0; +} + + +static void DoC_Probe(unsigned long physadr) +{ + unsigned long docptr; + struct DiskOnChip *this; + struct mtd_info *mtd; + int ChipID; + char namebuf[15]; + char *name = namebuf; + void (*initroutine)(struct mtd_info *) = NULL; + int initroutinedynamic = 0; + + docptr = (unsigned long)ioremap(physadr, 0x2000); + + if (!docptr) + return; + + if ((ChipID = doccheck(docptr, physadr))) { + + mtd = kmalloc(sizeof(struct DiskOnChip) + sizeof(struct mtd_info), GFP_KERNEL); + + if (!mtd) { + printk("Cannot allocate memory for data structures. Dropping.\n"); + iounmap((void *)docptr); + return; + } + + this = (struct DiskOnChip *)(&mtd[1]); + + memset((char *)mtd,0, sizeof(struct mtd_info)); + memset((char *)this, 0, sizeof(struct DiskOnChip)); + + mtd->priv = this; + this->virtadr = docptr; + this->physadr = physadr; + this->ChipID = ChipID; + sprintf(namebuf, "with ChipID %2.2X", ChipID); + + switch(ChipID) { + case DOC_ChipID_Doc2k: + name="2000"; +#ifdef CONFIG_MTD_DOC2000 + initroutine = &DoC2k_init; +#elif CONFIG_MODULES + initroutinedynamic=1; + initroutine = (void *)get_module_symbol(NULL, "DoC2k_init"); +#ifdef CONFIG_KMOD + if (!initroutine) { + request_module("doc2000"); + initroutine = (void *)get_module_symbol("doc2000", "DoC2k_init"); + } +#endif /* CONFIG_KMOD */ +#endif + break; + + case DOC_ChipID_DocMil: + name="Millennium"; +#ifdef CONFIG_MTD_DOC2001 + initroutine = &DocMil_init; +#elif CONFIG_MODULES + initroutinedynamic=1; + initroutine = (void *)get_module_symbol(NULL, "DoCMil_init"); +#ifdef CONFIG_KMOD + if (!initroutine) { + request_module("doc2001"); + initroutine = (void *)get_module_symbol("doc2001", "DoCMil_init"); + } +#endif /* CONFIG_KMOD */ +#endif + break; + } + if (initroutine) { + (*initroutine)(mtd); +#if defined(CONFIG_MODULES) && LINUX_VERSION_CODE >= 0x20400 + if (initroutinedynamic) + put_module_symbol(initroutine); +#endif + return; + } + printk("Cannot find driver for DiskOnChip %s at 0x%X\n", name, physadr); + } + iounmap((void *)docptr); +} + + +/**************************************************************************** + * + * Module stuff + * + ****************************************************************************/ + +#if LINUX_VERSION_CODE < 0x20300 +#ifdef MODULE +#define init_doc init_module +#endif +#define __exit +#endif + +int __init init_doc(void) +{ + int i; + + printk(KERN_NOTICE "M-Systems DiskOnChip driver. (C) 1999 Machine Vision Holdings, Inc.\n"); +#ifdef PRERELEASE + printk(KERN_INFO "$Id: docprobe.c,v 1.8 2000/06/26 20:40:53 dwmw2 Exp $\n"); +#endif + + for (i=0; doc_locations[i]; i++) { + DoC_Probe(doc_locations[i]); + } + + return 0; + +} + + +#if LINUX_VERSION_CODE > 0x20300 +module_init(init_doc); +#endif + |