--- zzzz-none-000/linux-2.4.17/drivers/mtd/chips/cfi_cmdset_0002.c 2001-10-25 07:07:09.000000000 +0000 +++ sangam-fb-401/linux-2.4.17/drivers/mtd/chips/cfi_cmdset_0002.c 2005-08-22 08:18:51.000000000 +0000 @@ -8,7 +8,7 @@ * * This code is GPL * - * $Id: cfi_cmdset_0002.c,v 1.52 2001/10/24 09:37:30 dwmw2 Exp $ + * $Id: cfi_cmdset_0002.c,v 1.2 2002/09/27 14:15:06 sneha Exp $ * */ @@ -26,7 +26,15 @@ #include #include +/*--- #define DEBUG_CFI_0002 ---*/ + #define AMD_BOOTLOC_BUG +#define USE_WRITE_BUFFER + +/* IMPORTANT: Define this flag to make write blocking, i.e the delay in + * do_write_onword will not relinquish time slice for the read (do_read_oneword) + * and erase (do_erase_oneblock) routines.*/ +#define BLOCKING_WRITE static int cfi_amdstd_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *); static int cfi_amdstd_write(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); @@ -58,6 +66,13 @@ __u8 major, minor; __u32 base = cfi->chips[0].start; +#ifdef DEBUG_CFI_0002 + printk(KERN_NOTICE "[cfi_cmdset_0002] name %s\n", map->name); + printk(KERN_NOTICE "[cfi_cmdset_0002] start 0x%u\n", cfi->chips[0].start); + printk(KERN_NOTICE "[cfi_cmdset_0002] interleave 0x%x\n", cfi->interleave); + printk(KERN_NOTICE "[cfi_cmdset_0002] device_type 0x%x\n", cfi->device_type); +#endif /*--- #ifdef DEBUG_CFI_0002 ---*/ + if (cfi->cfi_mode==1){ __u16 adr = primary?cfi->cfiq->P_ADR:cfi->cfiq->A_ADR; @@ -199,8 +214,8 @@ kfree(cfi->cmdset_priv); return NULL; } -#if 0 - // debug +#ifdef DEBUG_CFI_0002 + // debug for (i=0; inumeraseregions;i++){ printk("%d: offset=0x%x,size=0x%x,blocks=%d\n", i,mtd->eraseregions[i].offset, @@ -215,12 +230,13 @@ case 1: case 2: case 4: + case 8: #if 1 if (mtd->numeraseregions > 1) mtd->erase = cfi_amdstd_erase_varsize; else #endif - mtd->erase = cfi_amdstd_erase_onesize; + mtd->erase = cfi_amdstd_erase_onesize; mtd->read = cfi_amdstd_read; mtd->write = cfi_amdstd_write; break; @@ -331,6 +347,9 @@ struct cfi_private *cfi = map->fldrv_priv; DECLARE_WAITQUEUE(wait, current); int ret = 0; +#ifdef CFIDEV_BUSWIDTH_8 + int base = chip->start; +#endif /*--- #ifdef CFIDEV_BUSWIDTH_8 ---*/ retry: cfi_spin_lock(chip->mutex); @@ -360,27 +379,59 @@ adr += chip->start; ENABLE_VPP(map); +#ifdef CFIDEV_BUSWIDTH_8 + if (CFIDEV_BUSWIDTH == 8) { + if(cfi->interleave > 1) { + /* special case for 64 bit flash on a 32 bit OS + * need to determine which chip set to send the + unlock commands to + */ + if(!((adr & 0x00000007) < 4) ) { + base += 0x04; /* upper pair */ + } + } + } +#endif if (fast) { /* Unlock bypass */ - cfi_send_gen_cmd(0xA0, 0, chip->start, map, cfi, cfi->device_type, NULL); +#ifdef CFIDEV_BUSWIDTH_8 + if (CFIDEV_BUSWIDTH == 8) + cfi_send_word_cmd(0xA0, 0, base, map, cfi, cfi->device_type, NULL); + else +#endif /*--- #ifdef CFIDEV_BUSWIDTH_8 ---*/ + cfi_send_gen_cmd(0xA0, 0, chip->start, map, cfi, cfi->device_type, NULL); + } else { - cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); - cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); - cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); +#ifdef CFIDEV_BUSWIDTH_8 + if (CFIDEV_BUSWIDTH == 8) { + cfi_send_word_cmd(0xAA, cfi->addr_unlock1, base, map, cfi, CFI_DEVICETYPE_X8, NULL); + cfi_send_word_cmd(0x55, cfi->addr_unlock2, base, map, cfi, CFI_DEVICETYPE_X8, NULL); + cfi_send_word_cmd(0xA0, cfi->addr_unlock1, base, map, cfi, CFI_DEVICETYPE_X8, NULL); + } else +#endif /*--- #ifdef CFIDEV_BUSWIDTH_8 ---*/ + { + cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); + cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); + cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); + } } cfi_write(map, datum, adr); +#ifdef BLOCKING_WRITE + udelay(chip->word_write_time); +#else cfi_spin_unlock(chip->mutex); cfi_udelay(chip->word_write_time); cfi_spin_lock(chip->mutex); +#endif /* BLOCKING_WRITE */ Last[0] = cfi_read(map, adr); - // printk("Last[0] is %x\n", Last[0]); + /*--- printk("Last[0] is %x\n", Last[0]); ---*/ Last[1] = cfi_read(map, adr); - // printk("Last[1] is %x\n", Last[1]); + /*--- printk("Last[1] is %x\n", Last[1]); ---*/ Last[2] = cfi_read(map, adr); - // printk("Last[2] is %x\n", Last[2]); + /*--- printk("Last[2] is %x\n", Last[2]); ---*/ for (Count = 3; Last[(Count - 1) % 4] != Last[(Count - 2) % 4] && Count < 10000; Count++){ cfi_spin_unlock(chip->mutex); @@ -388,12 +439,12 @@ cfi_spin_lock(chip->mutex); Last[Count % 4] = cfi_read(map, adr); - // printk("Last[%d%%4] is %x\n", Count, Last[Count%4]); + printk("Last[%d%%4] is %x\n", Count, Last[Count%4]); } if (Last[(Count - 1) % 4] != datum){ - printk(KERN_WARNING "Last[%ld] is %x, datum is %x\n",(Count - 1) % 4,Last[(Count - 1) % 4],datum); - cfi_send_gen_cmd(0xF0, 0, chip->start, map, cfi, cfi->device_type, NULL); + printk(KERN_WARNING "Last[%ld] is %x, datum is %x\n",(Count - 1) % 4,Last[(Count - 1) % 4],datum); + cfi_send_gen_cmd(0xF0, 0, chip->start, map, cfi, cfi->device_type, NULL); DISABLE_VPP(map); ret = -EIO; } @@ -405,13 +456,178 @@ return ret; } -static int cfi_amdstd_write (struct mtd_info *mtd, loff_t to , size_t len, size_t *retlen, const u_char *buf) +#ifdef USE_WRITE_BUFFER +#define FLASH_BUFFER_SIZE 32 +static int do_write_buffer(struct mtd_info *mtd, struct flchip *chip, unsigned long adr, const u_char *buf, size_t *retlen) +{ + struct map_info *map = mtd->priv; + unsigned long timeo = jiffies + HZ; + struct cfi_private *cfi = map->fldrv_priv; + DECLARE_WAITQUEUE(wait, current); + + unsigned int sectorregion = 0; + unsigned long Count = 0; + int i, ret = 0; + + /*--- ermitteln der Sectorsize ---*/ + while (sectorregion < mtd->numeraseregions && adr >= mtd->eraseregions[sectorregion].offset) + sectorregion++; + sectorregion--; + + /*--- nicht ueber Sectorgrenzen schreiben ---*/ + if ((adr % mtd->eraseregions[sectorregion].erasesize) && (*retlen > (adr % mtd->eraseregions[sectorregion].erasesize))) { + *retlen -= adr % mtd->eraseregions[sectorregion].erasesize; + } + + /*--- nicht über die Grenze des Writebuffers schreiben ---*/ + if ((adr % FLASH_BUFFER_SIZE) && (*retlen > (FLASH_BUFFER_SIZE - (adr % FLASH_BUFFER_SIZE)))) { + *retlen = (FLASH_BUFFER_SIZE - (adr % FLASH_BUFFER_SIZE)); + } + + +retry: + cfi_spin_lock(chip->mutex); + + if (chip->state != FL_READY){ +#if 0 + printk(KERN_DEBUG "Waiting for chip to write, status = %d\n", chip->state); +#endif + set_current_state(TASK_UNINTERRUPTIBLE); + add_wait_queue(&chip->wq, &wait); + + cfi_spin_unlock(chip->mutex); + + schedule(); + remove_wait_queue(&chip->wq, &wait); +#if 0 + printk(KERN_DEBUG "Wake up to write:\n"); + if(signal_pending(current)) + return -EINTR; +#endif + timeo = jiffies + HZ; + + goto retry; + } + + chip->state = FL_WRITING; + + adr += chip->start; + ENABLE_VPP(map); + /*--- printk("[do_write_buffer] Adr: 0x%x len %d sectorsize 0x%x\n", adr, *retlen, mtd->eraseregions[sectorregion].erasesize); ---*/ + +#ifdef CFIDEV_BUSWIDTH_8 + if (CFIDEV_BUSWIDTH == 8) { + cfi_send_word_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); + cfi_send_word_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); + cfi_send_word_cmd(0x25, adr, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); + cfi_write(map, *retlen-1, adr); /*--- write buffercounter ---*/ + } else +#endif /*--- #ifdef CFIDEV_BUSWIDTH_8 ---*/ + { + cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); + cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); + cfi_send_gen_cmd(0x25, adr, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); + cfi_write(map, (*retlen>>1)-1, adr); /*--- write buffercounter ---*/ + } + + /*--- write data to buffer ---*/ + i = 0; + while (i < *retlen) { + __u32 datum; + + if (cfi_buswidth_is_1()) { + datum = *(__u8*)&buf[i]; + } else if (cfi_buswidth_is_2()) { + datum = *(__u16*)&buf[i]; + } else if (cfi_buswidth_is_4() || cfi_buswidth_is_8()) { + datum = *(__u32*)&buf[i]; + } else { + return -EINVAL; + } + + /*--- printk("[cfi_write] addr 0x%x val 0x%x\n", adr+i, datum); ---*/ + cfi_write(map, datum, adr+i); + i += CFIDEV_BUSWIDTH; + } + + /*--- write buffer command ---*/ + cfi_send_gen_cmd(0x29, adr, chip->start, map, cfi, cfi->device_type, NULL); + +#ifdef BLOCKING_WRITE + udelay(chip->word_write_time); +#else + cfi_spin_unlock(chip->mutex); + cfi_udelay(chip->word_write_time); + cfi_spin_lock(chip->mutex); +#endif /* BLOCKING_WRITE */ + + for (Count = 0; (cfi_read(map,adr) != cfi_read(map,adr)) && (Count < 10000); Count++) { +#ifdef BLOCKING_WRITE + udelay(chip->word_write_time); +#else + cfi_spin_unlock(chip->mutex); + cfi_udelay(10); + cfi_spin_lock(chip->mutex); +#endif /*--- #ifdef BLOCKING_WRITE ---*/ + } + + if (Count > 1000) + printk(KERN_WARNING "[flash do_write_buffer] Count=%d adr 0x%x=0x%x\n", Count, adr, cfi_read(map,adr)); + + /*--- test written data ---*/ + i = 0; + while (i < *retlen) { + __u32 datum; + + if (cfi_buswidth_is_1()) { + datum = *(__u8*)&buf[i]; + } else if (cfi_buswidth_is_2()) { + datum = *(__u16*)&buf[i]; + } else if (cfi_buswidth_is_4() || cfi_buswidth_is_8()) { + datum = *(__u32*)&buf[i]; + } else { + return -EINVAL; + } + + if (cfi_read(map, adr+i) != datum) { + printk(KERN_WARNING "\n", adr+i, cfi_read(map, adr+i), datum); + /*--- reset bufferwrite ---*/ + cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); + cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); + cfi_send_gen_cmd(0xF0, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); + /*--- reset flash ---*/ + cfi_send_gen_cmd(0xF0, 0, chip->start, map, cfi, cfi->device_type, NULL); + ret = -EIO; + break; + } + i += CFIDEV_BUSWIDTH; + } + + DISABLE_VPP(map); + chip->state = FL_READY; + wake_up(&chip->wq); + cfi_spin_unlock(chip->mutex); + + return ret; + +} +#endif /*--- #ifdef USE_WRITE_BUFFER ---*/ + +static int cfi_amdstd_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 cfi_private *cfi = map->fldrv_priv; int ret = 0; + int working_buswidth = CFIDEV_BUSWIDTH; int chipnum; unsigned long ofs, chipstart; +#ifdef USE_WRITE_BUFFER + int writebuffer = 0; + + if (cfi->cfiq->MaxBufWriteSize && ((1 << cfi->cfiq->MaxBufWriteSize) == FLASH_BUFFER_SIZE)) { + writebuffer = (1 << cfi->cfiq->MaxBufWriteSize); + } +#endif /*--- #ifdef USE_WRITE_BUFFER ---*/ *retlen = 0; if (!len) @@ -421,28 +637,30 @@ ofs = to - (chipnum << cfi->chipshift); chipstart = cfi->chips[chipnum].start; + if (CFIDEV_BUSWIDTH == 8) + working_buswidth = CFIDEV_BUSWIDTH / 2; + /* If it's not bus-aligned, do the first byte write */ - if (ofs & (CFIDEV_BUSWIDTH-1)) { - unsigned long bus_ofs = ofs & ~(CFIDEV_BUSWIDTH-1); + if (ofs & (working_buswidth-1)) { + unsigned long bus_ofs = ofs & ~(working_buswidth-1); int i = ofs - bus_ofs; int n = 0; u_char tmp_buf[4]; __u32 datum; - map->copy_from(map, tmp_buf, bus_ofs + cfi->chips[chipnum].start, CFIDEV_BUSWIDTH); - while (len && i < CFIDEV_BUSWIDTH) + map->copy_from(map, tmp_buf, bus_ofs + cfi->chips[chipnum].start, working_buswidth); + while (len && i < working_buswidth) tmp_buf[i++] = buf[n++], len--; if (cfi_buswidth_is_2()) { datum = *(__u16*)tmp_buf; - } else if (cfi_buswidth_is_4()) { + } else if (cfi_buswidth_is_4() || cfi_buswidth_is_8()) { datum = *(__u32*)tmp_buf; } else { return -EINVAL; /* should never happen, but be safe */ } - ret = do_write_oneword(map, &cfi->chips[chipnum], - bus_ofs, datum, 0); + ret = do_write_oneword(map, &cfi->chips[chipnum], bus_ofs, datum, 0); if (ret) return ret; @@ -459,58 +677,81 @@ } /* Go into unlock bypass mode */ - cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL); - cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL); - cfi_send_gen_cmd(0x20, cfi->addr_unlock1, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL); + if (cfi->fast_prog && !writebuffer) { + cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL); + cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL); + cfi_send_gen_cmd(0x20, cfi->addr_unlock1, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL); + } /* We are now aligned, write as much as possible */ - while(len >= CFIDEV_BUSWIDTH) { - __u32 datum; - - if (cfi_buswidth_is_1()) { - datum = *(__u8*)buf; - } else if (cfi_buswidth_is_2()) { - datum = *(__u16*)buf; - } else if (cfi_buswidth_is_4()) { - datum = *(__u32*)buf; - } else { - return -EINVAL; - } - ret = do_write_oneword(map, &cfi->chips[chipnum], - ofs, datum, cfi->fast_prog); - if (ret) { - if (cfi->fast_prog){ - /* Get out of unlock bypass mode */ - cfi_send_gen_cmd(0x90, 0, chipstart, map, cfi, cfi->device_type, NULL); - cfi_send_gen_cmd(0x00, 0, chipstart, map, cfi, cfi->device_type, NULL); - } - return ret; - } - - ofs += CFIDEV_BUSWIDTH; - buf += CFIDEV_BUSWIDTH; - (*retlen) += CFIDEV_BUSWIDTH; - len -= CFIDEV_BUSWIDTH; - - if (ofs >> cfi->chipshift) { - if (cfi->fast_prog){ - /* Get out of unlock bypass mode */ - cfi_send_gen_cmd(0x90, 0, chipstart, map, cfi, cfi->device_type, NULL); - cfi_send_gen_cmd(0x00, 0, chipstart, map, cfi, cfi->device_type, NULL); - } - - chipnum ++; - ofs = 0; - if (chipnum == cfi->numchips) - return 0; - chipstart = cfi->chips[chipnum].start; - if (cfi->fast_prog){ - /* Go into unlock bypass mode for next set of chips */ - cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL); - cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL); - cfi_send_gen_cmd(0x20, cfi->addr_unlock1, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL); - } - } + while(len >= working_buswidth) { +#ifdef USE_WRITE_BUFFER + if (writebuffer) { + unsigned int bytes; + + bytes = len > writebuffer ? writebuffer : len; + bytes &= ~1; + /*--- do_write_buffer unterstützt kein fast- Programming ---*/ + ret = do_write_buffer(mtd, &cfi->chips[chipnum], ofs, buf, &bytes); + if (ret) + return ret; + + ofs += bytes; + buf += bytes; + (*retlen) += bytes; + len -= bytes; + + } else { +#endif /*--- #ifdef USE_WRITE_BUFFER ---*/ + __u32 datum; + + if (cfi_buswidth_is_1()) { + datum = *(__u8*)buf; + } else if (cfi_buswidth_is_2()) { + datum = *(__u16*)buf; + } else if (cfi_buswidth_is_4() || cfi_buswidth_is_8()) { + datum = *(__u32*)buf; + } else { + return -EINVAL; + } + ret = do_write_oneword(map, &cfi->chips[chipnum], ofs, datum, cfi->fast_prog); + if (ret) { + if (cfi->fast_prog){ + /* Get out of unlock bypass mode */ + cfi_send_gen_cmd(0x90, 0, chipstart, map, cfi, cfi->device_type, NULL); + cfi_send_gen_cmd(0x00, 0, chipstart, map, cfi, cfi->device_type, NULL); + } + return ret; + } + + ofs += working_buswidth; + buf += working_buswidth; + (*retlen) += working_buswidth; + len -= working_buswidth; + +#ifdef USE_WRITE_BUFFER + } +#endif /*--- #ifdef USE_WRITE_BUFFER ---*/ + /*--- falls wir den naechsten chip beschreiben muessen ---*/ + if (ofs >> cfi->chipshift) { + if (cfi->fast_prog){ + /* Get out of unlock bypass mode */ + cfi_send_gen_cmd(0x90, 0, chipstart, map, cfi, cfi->device_type, NULL); + cfi_send_gen_cmd(0x00, 0, chipstart, map, cfi, cfi->device_type, NULL); + } + + chipnum ++; + ofs = 0; + if (chipnum == cfi->numchips) + return 0; + chipstart = cfi->chips[chipnum].start; + if (cfi->fast_prog){ + /* Go into unlock bypass mode for next set of chips */ + cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL); + cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL); + cfi_send_gen_cmd(0x20, cfi->addr_unlock1, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL); + } + } } if (cfi->fast_prog){ @@ -519,25 +760,24 @@ cfi_send_gen_cmd(0x00, 0, chipstart, map, cfi, cfi->device_type, NULL); } - if (len & (CFIDEV_BUSWIDTH-1)) { + if (len & (working_buswidth-1)) { int i = 0, n = 0; - u_char tmp_buf[4]; + u_char tmp_buf[CFIDEV_BUSWIDTH]; __u32 datum; - map->copy_from(map, tmp_buf, ofs + cfi->chips[chipnum].start, CFIDEV_BUSWIDTH); + map->copy_from(map, tmp_buf, ofs + cfi->chips[chipnum].start, working_buswidth); while (len--) tmp_buf[i++] = buf[n++]; if (cfi_buswidth_is_2()) { datum = *(__u16*)tmp_buf; - } else if (cfi_buswidth_is_4()) { + } else if (cfi_buswidth_is_4() || cfi_buswidth_is_8()) { datum = *(__u32*)tmp_buf; } else { return -EINVAL; /* should never happen, but be safe */ } - ret = do_write_oneword(map, &cfi->chips[chipnum], - ofs, datum, 0); + ret = do_write_oneword(map, &cfi->chips[chipnum], ofs, datum, 0); if (ret) return ret; @@ -585,7 +825,9 @@ cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); cfi_write(map, CMD(0x30), adr); - + if (CFIDEV_BUSWIDTH == 8) + cfi_write(map, CMD(0x30), adr+0x04); + timeo = jiffies + (HZ*20); cfi_spin_unlock(chip->mutex);