[patch] collie: fixup mtd a bit
Pavel Machek
pavel at ucw.cz
Tue Nov 1 18:33:20 EST 2005
Get collie mtd support closer to working/clean state.
Signed-off-by: Pavel Machek <pavel at suse.cz>
---
commit 3fe09bee0821649805849b89c3329d3f05874cae
tree b089cb58a8d4af8480ed08a3f772ad47753946e7
parent 8ab89cd19ec120410f6d259348d4ce8a5848fd7f
author <pavel at amd.(none)> Wed, 02 Nov 2005 00:31:50 +0100
committer <pavel at amd.(none)> Wed, 02 Nov 2005 00:31:50 +0100
drivers/mtd/chips/sharp.c | 192 ++++++++++++++++++++++++++-------------------
drivers/mtd/maps/Kconfig | 2
2 files changed, 113 insertions(+), 81 deletions(-)
diff --git a/drivers/mtd/chips/sharp.c b/drivers/mtd/chips/sharp.c
--- a/drivers/mtd/chips/sharp.c
+++ b/drivers/mtd/chips/sharp.c
@@ -25,6 +25,7 @@
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/errno.h>
+#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/mtd/map.h>
#include <linux/mtd/mtd.h>
@@ -59,9 +60,11 @@
#define SR_ERRORS (SR_ERROR_ERASE|SR_ERROR_WRITE|SR_VPP|SR_PROTECT)
+#define BLOCK_MASK 0xfffe0000
+
/* Configuration options */
-#undef AUTOUNLOCK /* automatically unlocks blocks before erasing */
+#define AUTOUNLOCK /* automatically unlocks blocks before erasing */
struct mtd_info *sharp_probe(struct map_info *);
@@ -82,7 +85,7 @@ static int sharp_write_oneword(struct ma
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,
+static inline void sharp_unlock_oneblock(struct map_info *map, struct flchip *chip,
unsigned long adr);
#endif
@@ -143,7 +146,7 @@ struct mtd_info *sharp_probe(struct map_
mtd->name = map->name;
memset(sharp, 0, sizeof(*sharp));
- sharp->chipshift = 23;
+ sharp->chipshift = 24;
sharp->numchips = 1;
sharp->chips[0].start = 0;
sharp->chips[0].state = FL_READY;
@@ -170,10 +173,9 @@ static int sharp_probe_map(struct map_in
map_write32(map, CMD_READ_ID, base+0);
- read0=map_read32(map, base+0);
- read4=map_read32(map, base+4);
- if(read0 == 0x89898989){
- printk("Looks like sharp flash\n");
+ read0 = map_read32(map, base+0);
+ read4 = map_read32(map, base+4);
+ if (read0 == 0x00b000b0) {
switch(read4){
case 0xaaaaaaaa:
case 0xa0a0a0a0:
@@ -188,22 +190,20 @@ static int sharp_probe_map(struct map_in
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;
+ case 0x00b000b0:
+ /* a6 - LH28F640BFHE 8 64k * 2 chip blocks*/
+ mtd->erasesize = 0x10000 * width / 2;
+ mtd->size = 0x800000 * width / 2;
return width;
-#endif
default:
printk("Sort-of looks like sharp flash, 0x%08x 0x%08x\n",
read0,read4);
}
- }else if((map_read32(map, base+0) == CMD_READ_ID)){
+ } else if ((map_read32(map, base+0) == CMD_READ_ID)){
/* RAM, probably */
printk("Looks like RAM\n");
map_write32(map, tmp, base+0);
- }else{
+ } else {
printk("Doesn't look like sharp flash, 0x%08x 0x%08x\n",
read0,read4);
}
@@ -214,7 +214,7 @@ static int sharp_probe_map(struct map_in
/* This function returns with the chip->mutex lock held. */
static int sharp_wait(struct map_info *map, struct flchip *chip)
{
- __u16 status;
+ __u32 status;
unsigned long timeo = jiffies + HZ;
DECLARE_WAITQUEUE(wait, current);
int adr = 0;
@@ -222,29 +222,30 @@ static int sharp_wait(struct map_info *m
retry:
spin_lock_bh(chip->mutex);
- switch(chip->state){
+ switch (chip->state) {
case FL_READY:
- map_write32(map,CMD_READ_STATUS,adr);
+ map_write32(map, CMD_READ_STATUS, adr);
chip->state = FL_STATUS;
case FL_STATUS:
status = map_read32(map,adr);
-//printk("status=%08x\n",status);
-
- udelay(100);
- if((status & SR_READY)!=SR_READY){
-//printk(".status=%08x\n",status);
- udelay(100);
+ if ((status & SR_READY) == SR_READY)
+ break;
+ spin_unlock_bh(chip->mutex);
+ if (time_after(jiffies, timeo)) {
+ printk("Waiting for chip to be ready timed out in erase\n");
+ return -EIO;
}
- break;
+ udelay(1);
+ goto retry;
default:
- printk("Waiting for chip\n");
-
set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&chip->wq, &wait);
spin_unlock_bh(chip->mutex);
- schedule();
+ udelay(1);
+
+ set_current_state(TASK_RUNNING);
remove_wait_queue(&chip->wq, &wait);
if(signal_pending(current))
@@ -255,7 +256,7 @@ retry:
goto retry;
}
- map_write32(map,CMD_RESET, adr);
+ map_write32(map, CMD_RESET, adr);
chip->state = FL_READY;
@@ -349,12 +350,13 @@ static int sharp_write_oneword(struct ma
unsigned long adr, __u32 datum)
{
int ret;
- int timeo;
int try;
int i;
- int status = 0;
+ u32 status = 0;
ret = sharp_wait(map,chip);
+ if (ret < 0)
+ return ret;
for(try=0;try<10;try++){
map_write32(map,CMD_BYTE_WRITE,adr);
@@ -363,14 +365,21 @@ static int sharp_write_oneword(struct ma
chip->state = FL_WRITING;
- timeo = jiffies + (HZ/2);
-
map_write32(map,CMD_READ_STATUS,adr);
for(i=0;i<100;i++){
status = map_read32(map,adr);
if((status & SR_READY)==SR_READY)
break;
}
+#ifdef AUTOUNLOCK
+ if (status & SR_PROTECT) { /* lock block */
+ map_write32(map, CMD_CLEAR_STATUS, adr);
+ sharp_unlock_oneblock(map,chip,adr);
+ map_write32(map, CMD_CLEAR_STATUS, adr);
+ map_write32(map, CMD_RESET, adr);
+ continue;
+ }
+#endif
if(i==100){
printk("sharp: timed out writing\n");
}
@@ -385,8 +394,7 @@ static int sharp_write_oneword(struct ma
map_write32(map,CMD_RESET,adr);
chip->state = FL_READY;
- wake_up(&chip->wq);
- spin_unlock_bh(chip->mutex);
+ sharp_release(chip);
return 0;
}
@@ -398,7 +406,6 @@ static int sharp_erase(struct mtd_info *
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))
@@ -414,8 +421,13 @@ static int sharp_erase(struct mtd_info *
ret = sharp_erase_oneblock(map, &sharp->chips[chipnum], adr);
if(ret)return ret;
- adr += mtd->erasesize;
- len -= mtd->erasesize;
+ if (adr >= 0xfe0000) {
+ adr += mtd->erasesize / 8;
+ len -= mtd->erasesize / 8;
+ } else {
+ adr += mtd->erasesize;
+ len -= mtd->erasesize;
+ }
if(adr >> sharp->chipshift){
adr = 0;
chipnum++;
@@ -430,7 +442,7 @@ static int sharp_erase(struct mtd_info *
return 0;
}
-static int sharp_do_wait_for_ready(struct map_info *map, struct flchip *chip,
+static inline int sharp_do_wait_for_ready(struct map_info *map, struct flchip *chip,
unsigned long adr)
{
int ret;
@@ -441,7 +453,7 @@ static int sharp_do_wait_for_ready(struc
map_write32(map,CMD_READ_STATUS,adr);
status = map_read32(map,adr);
- timeo = jiffies + HZ;
+ timeo = jiffies + HZ * 10;
while(time_before(jiffies, timeo)){
map_write32(map,CMD_READ_STATUS,adr);
@@ -453,19 +465,15 @@ static int sharp_do_wait_for_ready(struc
set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&chip->wq, &wait);
- //spin_unlock_bh(chip->mutex);
+ 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;
- }
-
+ spin_lock_bh(chip->mutex);
+
+ remove_wait_queue(&chip->wq, &wait);
+ set_current_state(TASK_RUNNING);
}
ret = -ETIME;
out:
@@ -476,11 +484,11 @@ static int sharp_erase_oneblock(struct m
unsigned long adr)
{
int ret;
- //int timeo;
- int status;
- //int i;
+ u32 status;
-//printk("sharp_erase_oneblock()\n");
+ ret = sharp_wait(map,chip);
+ if (ret < 0)
+ return ret;
#ifdef AUTOUNLOCK
/* This seems like a good place to do an unlock */
@@ -493,7 +501,10 @@ static int sharp_erase_oneblock(struct m
chip->state = FL_ERASING;
ret = sharp_do_wait_for_ready(map,chip,adr);
- if(ret<0)return ret;
+ if(ret<0) {
+ spin_unlock_bh(chip->mutex);
+ return ret;
+ }
map_write32(map,CMD_READ_STATUS,adr);
status = map_read32(map,adr);
@@ -501,43 +512,30 @@ static int sharp_erase_oneblock(struct m
if(!(status&SR_ERRORS)){
map_write32(map,CMD_RESET,adr);
chip->state = FL_READY;
- //spin_unlock_bh(chip->mutex);
+ spin_unlock_bh(chip->mutex);
return 0;
}
printk("sharp: error erasing block at addr=%08lx status=%08x\n",adr,status);
map_write32(map,CMD_CLEAR_STATUS,adr);
- //spin_unlock_bh(chip->mutex);
+ sharp_release(chip);
return -EIO;
}
#ifdef AUTOUNLOCK
-static void sharp_unlock_oneblock(struct map_info *map, struct flchip *chip,
+static inline void sharp_unlock_oneblock(struct map_info *map, struct flchip *chip,
unsigned long adr)
{
- int i;
- int status;
+ u32 status;
- map_write32(map,CMD_CLEAR_BLOCK_LOCKS_1,adr);
- map_write32(map,CMD_CLEAR_BLOCK_LOCKS_2,adr);
+ map_write32(map,CMD_CLEAR_BLOCK_LOCKS_1,adr & BLOCK_MASK);
+ map_write32(map,CMD_CLEAR_BLOCK_LOCKS_2,adr & BLOCK_MASK);
- udelay(100);
+ sharp_do_wait_for_ready(map,chip,adr);
status = map_read32(map,adr);
- printk("status=%08x\n",status);
-
- for(i=0;i<1000;i++){
- //map_write32(map,CMD_READ_STATUS,adr);
- status = map_read32(map,adr);
- if((status & SR_READY)==SR_READY)
- break;
- udelay(100);
- }
- if(i==1000){
- printk("sharp: timed out unlocking block\n");
- }
if(!(status&SR_ERRORS)){
map_write32(map,CMD_RESET,adr);
@@ -552,25 +550,59 @@ static void sharp_unlock_oneblock(struct
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;
+ struct map_info *map = mtd->priv;
+ struct sharp_info *sharp = map->fldrv_priv;
+ int i;
+ struct flchip *chip;
+ int ret = 0;
+
+ for (i = 0; !ret && i < sharp->numchips; i++) {
+ chip = &sharp->chips[i];
+ ret = sharp_wait(map,chip);
+
+ if (ret) {
+ ret = -EAGAIN;
+ } else {
+ chip->state = FL_PM_SUSPENDED;
+ spin_unlock_bh(chip->mutex);
+ }
+ }
+ return ret;
}
static void sharp_resume(struct mtd_info *mtd)
{
- printk("sharp_resume()\n");
-
+ struct map_info *map = mtd->priv;
+ struct sharp_info *sharp = map->fldrv_priv;
+ int i;
+ struct flchip *chip;
+
+ for (i = 0; i < sharp->numchips; i++) {
+ chip = &sharp->chips[i];
+
+ spin_lock_bh(chip->mutex);
+
+ if (chip->state == FL_PM_SUSPENDED) {
+ /* We need to force it back to a known state */
+ map_write32(map, CMD_RESET, chip->start);
+ chip->state = FL_READY;
+ wake_up(&chip->wq);
+ }
+
+ spin_unlock_bh(chip->mutex);
+ }
}
static void sharp_destroy(struct mtd_info *mtd)
{
- printk("sharp_destroy()\n");
+ struct map_info *map = mtd->priv;
+ struct sharp_info *sharp = map->fldrv_priv;
+ kfree(sharp);
}
int __init sharp_probe_init(void)
diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig
--- a/drivers/mtd/maps/Kconfig
+++ b/drivers/mtd/maps/Kconfig
@@ -412,7 +412,7 @@ config MTD_CDB89712
config MTD_SA1100
tristate "CFI Flash device mapped on StrongARM SA11x0"
- depends on ARM && MTD_CFI && ARCH_SA1100 && MTD_PARTITIONS
+ depends on ARM && (MTD_CFI || MTD_SHARP) && ARCH_SA1100 && MTD_PARTITIONS
help
This enables access to the flash chips on most platforms based on
the SA1100 and SA1110, including the Assabet and the Compaq iPAQ.
--
Thanks, Sharp!
More information about the linux-mtd
mailing list