diff options
Diffstat (limited to 'drivers/mtd/chips/sharp.c')
-rw-r--r-- | drivers/mtd/chips/sharp.c | 601 |
1 files changed, 0 insertions, 601 deletions
diff --git a/drivers/mtd/chips/sharp.c b/drivers/mtd/chips/sharp.c deleted file mode 100644 index c9cd3d2..0000000 --- a/drivers/mtd/chips/sharp.c +++ /dev/null @@ -1,601 +0,0 @@ -/* - * MTD chip driver for pre-CFI Sharp flash chips - * - * Copyright 2000,2001 David A. Schleef <ds@schleef.org> - * 2000,2001 Lineo, Inc. - * - * $Id: sharp.c,v 1.17 2005/11/29 14:28:28 gleixner Exp $ - * - * Devices supported: - * LH28F016SCT Symmetrical block flash memory, 2Mx8 - * LH28F008SCT Symmetrical block flash memory, 1Mx8 - * - * Documentation: - * http://www.sharpmeg.com/datasheets/memic/flashcmp/ - * http://www.sharpmeg.com/datasheets/memic/flashcmp/01symf/16m/016sctl9.pdf - * 016sctl9.pdf - * - * Limitations: - * This driver only supports 4x1 arrangement of chips. - * Not tested on anything but PowerPC. - */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/types.h> -#include <linux/sched.h> -#include <linux/errno.h> -#include <linux/interrupt.h> -#include <linux/mtd/map.h> -#include <linux/mtd/mtd.h> -#include <linux/mtd/cfi.h> -#include <linux/delay.h> -#include <linux/init.h> -#include <linux/slab.h> - -#define CMD_RESET 0xffffffff -#define CMD_READ_ID 0x90909090 -#define CMD_READ_STATUS 0x70707070 -#define CMD_CLEAR_STATUS 0x50505050 -#define CMD_BLOCK_ERASE_1 0x20202020 -#define CMD_BLOCK_ERASE_2 0xd0d0d0d0 -#define CMD_BYTE_WRITE 0x40404040 -#define CMD_SUSPEND 0xb0b0b0b0 -#define CMD_RESUME 0xd0d0d0d0 -#define CMD_SET_BLOCK_LOCK_1 0x60606060 -#define CMD_SET_BLOCK_LOCK_2 0x01010101 -#define CMD_SET_MASTER_LOCK_1 0x60606060 -#define CMD_SET_MASTER_LOCK_2 0xf1f1f1f1 -#define CMD_CLEAR_BLOCK_LOCKS_1 0x60606060 -#define CMD_CLEAR_BLOCK_LOCKS_2 0xd0d0d0d0 - -#define SR_READY 0x80808080 // 1 = ready -#define SR_ERASE_SUSPEND 0x40404040 // 1 = block erase suspended -#define SR_ERROR_ERASE 0x20202020 // 1 = error in block erase or clear lock bits -#define SR_ERROR_WRITE 0x10101010 // 1 = error in byte write or set lock bit -#define SR_VPP 0x08080808 // 1 = Vpp is low -#define SR_WRITE_SUSPEND 0x04040404 // 1 = byte write suspended -#define SR_PROTECT 0x02020202 // 1 = lock bit set -#define SR_RESERVED 0x01010101 - -#define SR_ERRORS (SR_ERROR_ERASE|SR_ERROR_WRITE|SR_VPP|SR_PROTECT) - -/* Configuration options */ - -#undef AUTOUNLOCK /* automatically unlocks blocks before erasing */ - -static struct mtd_info *sharp_probe(struct map_info *); - -static int sharp_probe_map(struct map_info *map,struct mtd_info *mtd); - -static int sharp_read(struct mtd_info *mtd, loff_t from, size_t len, - size_t *retlen, u_char *buf); -static int sharp_write(struct mtd_info *mtd, loff_t from, size_t len, - size_t *retlen, const u_char *buf); -static int sharp_erase(struct mtd_info *mtd, struct erase_info *instr); -static void sharp_sync(struct mtd_info *mtd); -static int sharp_suspend(struct mtd_info *mtd); -static void sharp_resume(struct mtd_info *mtd); -static void sharp_destroy(struct mtd_info *mtd); - -static int sharp_write_oneword(struct map_info *map, struct flchip *chip, - unsigned long adr, __u32 datum); -static int sharp_erase_oneblock(struct map_info *map, struct flchip *chip, - unsigned long adr); -#ifdef AUTOUNLOCK -static void sharp_unlock_oneblock(struct map_info *map, struct flchip *chip, - unsigned long adr); -#endif - - -struct sharp_info{ - struct flchip *chip; - int bogus; - int chipshift; - int numchips; - struct flchip chips[1]; -}; - -static void sharp_destroy(struct mtd_info *mtd); - -static struct mtd_chip_driver sharp_chipdrv = { - .probe = sharp_probe, - .destroy = sharp_destroy, - .name = "sharp", - .module = THIS_MODULE -}; - - -static struct mtd_info *sharp_probe(struct map_info *map) -{ - struct mtd_info *mtd = NULL; - struct sharp_info *sharp = NULL; - int width; - - mtd = kzalloc(sizeof(*mtd), GFP_KERNEL); - if(!mtd) - return NULL; - - sharp = kzalloc(sizeof(*sharp), GFP_KERNEL); - if(!sharp) { - kfree(mtd); - return NULL; - } - - width = sharp_probe_map(map,mtd); - if(!width){ - kfree(mtd); - kfree(sharp); - return NULL; - } - - mtd->priv = map; - mtd->type = MTD_NORFLASH; - mtd->erase = sharp_erase; - mtd->read = sharp_read; - mtd->write = sharp_write; - mtd->sync = sharp_sync; - mtd->suspend = sharp_suspend; - mtd->resume = sharp_resume; - mtd->flags = MTD_CAP_NORFLASH; - mtd->writesize = 1; - mtd->name = map->name; - - sharp->chipshift = 23; - sharp->numchips = 1; - sharp->chips[0].start = 0; - sharp->chips[0].state = FL_READY; - sharp->chips[0].mutex = &sharp->chips[0]._spinlock; - sharp->chips[0].word_write_time = 0; - init_waitqueue_head(&sharp->chips[0].wq); - spin_lock_init(&sharp->chips[0]._spinlock); - - map->fldrv = &sharp_chipdrv; - map->fldrv_priv = sharp; - - __module_get(THIS_MODULE); - return mtd; -} - -static inline void sharp_send_cmd(struct map_info *map, unsigned long cmd, unsigned long adr) -{ - map_word map_cmd; - map_cmd.x[0] = cmd; - map_write(map, map_cmd, adr); -} - -static int sharp_probe_map(struct map_info *map,struct mtd_info *mtd) -{ - map_word tmp, read0, read4; - unsigned long base = 0; - int width = 4; - - tmp = map_read(map, base+0); - - sharp_send_cmd(map, CMD_READ_ID, base+0); - - read0 = map_read(map, base+0); - read4 = map_read(map, base+4); - if(read0.x[0] == 0x89898989){ - printk("Looks like sharp flash\n"); - switch(read4.x[0]){ - case 0xaaaaaaaa: - case 0xa0a0a0a0: - /* aa - LH28F016SCT-L95 2Mx8, 32 64k blocks*/ - /* a0 - LH28F016SCT-Z4 2Mx8, 32 64k blocks*/ - mtd->erasesize = 0x10000 * width; - mtd->size = 0x200000 * width; - return width; - case 0xa6a6a6a6: - /* a6 - LH28F008SCT-L12 1Mx8, 16 64k blocks*/ - /* a6 - LH28F008SCR-L85 1Mx8, 16 64k blocks*/ - mtd->erasesize = 0x10000 * width; - mtd->size = 0x100000 * width; - return width; -#if 0 - case 0x00000000: /* unknown */ - /* XX - LH28F004SCT 512kx8, 8 64k blocks*/ - mtd->erasesize = 0x10000 * width; - mtd->size = 0x80000 * width; - return width; -#endif - default: - printk("Sort-of looks like sharp flash, 0x%08lx 0x%08lx\n", - read0.x[0], read4.x[0]); - } - }else if((map_read(map, base+0).x[0] == CMD_READ_ID)){ - /* RAM, probably */ - printk("Looks like RAM\n"); - map_write(map, tmp, base+0); - }else{ - printk("Doesn't look like sharp flash, 0x%08lx 0x%08lx\n", - read0.x[0], read4.x[0]); - } - - return 0; -} - -/* This function returns with the chip->mutex lock held. */ -static int sharp_wait(struct map_info *map, struct flchip *chip) -{ - int i; - map_word status; - unsigned long timeo = jiffies + HZ; - DECLARE_WAITQUEUE(wait, current); - int adr = 0; - -retry: - spin_lock_bh(chip->mutex); - - switch(chip->state){ - case FL_READY: - sharp_send_cmd(map, CMD_READ_STATUS, adr); - chip->state = FL_STATUS; - case FL_STATUS: - for(i=0;i<100;i++){ - status = map_read(map, adr); - if((status.x[0] & SR_READY)==SR_READY) - break; - udelay(1); - } - break; - default: - printk("Waiting for chip\n"); - - set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue(&chip->wq, &wait); - - spin_unlock_bh(chip->mutex); - - schedule(); - remove_wait_queue(&chip->wq, &wait); - - if(signal_pending(current)) - return -EINTR; - - timeo = jiffies + HZ; - - goto retry; - } - - sharp_send_cmd(map, CMD_RESET, adr); - - chip->state = FL_READY; - - return 0; -} - -static void sharp_release(struct flchip *chip) -{ - wake_up(&chip->wq); - spin_unlock_bh(chip->mutex); -} - -static int sharp_read(struct mtd_info *mtd, loff_t from, size_t len, - size_t *retlen, u_char *buf) -{ - struct map_info *map = mtd->priv; - struct sharp_info *sharp = map->fldrv_priv; - int chipnum; - int ret = 0; - int ofs = 0; - - chipnum = (from >> sharp->chipshift); - ofs = from & ((1 << sharp->chipshift)-1); - - *retlen = 0; - - while(len){ - unsigned long thislen; - - if(chipnum>=sharp->numchips) - break; - - thislen = len; - if(ofs+thislen >= (1<<sharp->chipshift)) - thislen = (1<<sharp->chipshift) - ofs; - - ret = sharp_wait(map,&sharp->chips[chipnum]); - if(ret<0) - break; - - map_copy_from(map,buf,ofs,thislen); - - sharp_release(&sharp->chips[chipnum]); - - *retlen += thislen; - len -= thislen; - buf += thislen; - - ofs = 0; - chipnum++; - } - return ret; -} - -static int sharp_write(struct mtd_info *mtd, loff_t to, size_t len, - size_t *retlen, const u_char *buf) -{ - struct map_info *map = mtd->priv; - struct sharp_info *sharp = map->fldrv_priv; - int ret = 0; - int i,j; - int chipnum; - unsigned long ofs; - union { u32 l; unsigned char uc[4]; } tbuf; - - *retlen = 0; - - while(len){ - tbuf.l = 0xffffffff; - chipnum = to >> sharp->chipshift; - ofs = to & ((1<<sharp->chipshift)-1); - - j=0; - for(i=ofs&3;i<4 && len;i++){ - tbuf.uc[i] = *buf; - buf++; - to++; - len--; - j++; - } - sharp_write_oneword(map, &sharp->chips[chipnum], ofs&~3, tbuf.l); - if(ret<0) - return ret; - (*retlen)+=j; - } - - return 0; -} - -static int sharp_write_oneword(struct map_info *map, struct flchip *chip, - unsigned long adr, __u32 datum) -{ - int ret; - int timeo; - int try; - int i; - map_word data, status; - - status.x[0] = 0; - ret = sharp_wait(map,chip); - - for(try=0;try<10;try++){ - sharp_send_cmd(map, CMD_BYTE_WRITE, adr); - /* cpu_to_le32 -> hack to fix the writel be->le conversion */ - data.x[0] = cpu_to_le32(datum); - map_write(map, data, adr); - - chip->state = FL_WRITING; - - timeo = jiffies + (HZ/2); - - sharp_send_cmd(map, CMD_READ_STATUS, adr); - for(i=0;i<100;i++){ - status = map_read(map, adr); - if((status.x[0] & SR_READY) == SR_READY) - break; - } - if(i==100){ - printk("sharp: timed out writing\n"); - } - - if(!(status.x[0] & SR_ERRORS)) - break; - - printk("sharp: error writing byte at addr=%08lx status=%08lx\n", adr, status.x[0]); - - sharp_send_cmd(map, CMD_CLEAR_STATUS, adr); - } - sharp_send_cmd(map, CMD_RESET, adr); - chip->state = FL_READY; - - wake_up(&chip->wq); - spin_unlock_bh(chip->mutex); - - return 0; -} - -static int sharp_erase(struct mtd_info *mtd, struct erase_info *instr) -{ - struct map_info *map = mtd->priv; - struct sharp_info *sharp = map->fldrv_priv; - unsigned long adr,len; - int chipnum, ret=0; - -//printk("sharp_erase()\n"); - 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; - - chipnum = instr->addr >> sharp->chipshift; - adr = instr->addr & ((1<<sharp->chipshift)-1); - len = instr->len; - - while(len){ - ret = sharp_erase_oneblock(map, &sharp->chips[chipnum], adr); - if(ret)return ret; - - adr += mtd->erasesize; - len -= mtd->erasesize; - if(adr >> sharp->chipshift){ - adr = 0; - chipnum++; - if(chipnum>=sharp->numchips) - break; - } - } - - instr->state = MTD_ERASE_DONE; - mtd_erase_callback(instr); - - return 0; -} - -static int sharp_do_wait_for_ready(struct map_info *map, struct flchip *chip, - unsigned long adr) -{ - int ret; - unsigned long timeo; - map_word status; - DECLARE_WAITQUEUE(wait, current); - - sharp_send_cmd(map, CMD_READ_STATUS, adr); - status = map_read(map, adr); - - timeo = jiffies + HZ; - - while(time_before(jiffies, timeo)){ - sharp_send_cmd(map, CMD_READ_STATUS, adr); - status = map_read(map, adr); - if((status.x[0] & SR_READY)==SR_READY){ - ret = 0; - goto out; - } - set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue(&chip->wq, &wait); - - //spin_unlock_bh(chip->mutex); - - schedule_timeout(1); - schedule(); - remove_wait_queue(&chip->wq, &wait); - - //spin_lock_bh(chip->mutex); - - if (signal_pending(current)){ - ret = -EINTR; - goto out; - } - - } - ret = -ETIME; -out: - return ret; -} - -static int sharp_erase_oneblock(struct map_info *map, struct flchip *chip, - unsigned long adr) -{ - int ret; - //int timeo; - map_word status; - //int i; - -//printk("sharp_erase_oneblock()\n"); - -#ifdef AUTOUNLOCK - /* This seems like a good place to do an unlock */ - sharp_unlock_oneblock(map,chip,adr); -#endif - - sharp_send_cmd(map, CMD_BLOCK_ERASE_1, adr); - sharp_send_cmd(map, CMD_BLOCK_ERASE_2, adr); - - chip->state = FL_ERASING; - - ret = sharp_do_wait_for_ready(map,chip,adr); - if(ret<0)return ret; - - sharp_send_cmd(map, CMD_READ_STATUS, adr); - status = map_read(map, adr); - - if(!(status.x[0] & SR_ERRORS)){ - sharp_send_cmd(map, CMD_RESET, adr); - chip->state = FL_READY; - //spin_unlock_bh(chip->mutex); - return 0; - } - - printk("sharp: error erasing block at addr=%08lx status=%08lx\n", adr, status.x[0]); - sharp_send_cmd(map, CMD_CLEAR_STATUS, adr); - - //spin_unlock_bh(chip->mutex); - - return -EIO; -} - -#ifdef AUTOUNLOCK -static void sharp_unlock_oneblock(struct map_info *map, struct flchip *chip, - unsigned long adr) -{ - int i; - map_word status; - - sharp_send_cmd(map, CMD_CLEAR_BLOCK_LOCKS_1, adr); - sharp_send_cmd(map, CMD_CLEAR_BLOCK_LOCKS_2, adr); - - udelay(100); - - status = map_read(map, adr); - printk("status=%08lx\n", status.x[0]); - - for(i=0;i<1000;i++){ - //sharp_send_cmd(map, CMD_READ_STATUS, adr); - status = map_read(map, adr); - if((status.x[0] & SR_READY) == SR_READY) - break; - udelay(100); - } - if(i==1000){ - printk("sharp: timed out unlocking block\n"); - } - - if(!(status.x[0] & SR_ERRORS)){ - sharp_send_cmd(map, CMD_RESET, adr); - chip->state = FL_READY; - return; - } - - printk("sharp: error unlocking block at addr=%08lx status=%08lx\n", adr, status.x[0]); - sharp_send_cmd(map, CMD_CLEAR_STATUS, adr); -} -#endif - -static void sharp_sync(struct mtd_info *mtd) -{ - //printk("sharp_sync()\n"); -} - -static int sharp_suspend(struct mtd_info *mtd) -{ - printk("sharp_suspend()\n"); - return -EINVAL; -} - -static void sharp_resume(struct mtd_info *mtd) -{ - printk("sharp_resume()\n"); - -} - -static void sharp_destroy(struct mtd_info *mtd) -{ - printk("sharp_destroy()\n"); - -} - -static int __init sharp_probe_init(void) -{ - printk("MTD Sharp chip driver <ds@lineo.com>\n"); - - register_mtd_chip_driver(&sharp_chipdrv); - - return 0; -} - -static void __exit sharp_probe_exit(void) -{ - unregister_mtd_chip_driver(&sharp_chipdrv); -} - -module_init(sharp_probe_init); -module_exit(sharp_probe_exit); - - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("David Schleef <ds@schleef.org>"); -MODULE_DESCRIPTION("Old MTD chip driver for pre-CFI Sharp flash chips"); |