⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 jedec.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
   #undef flwrite}/* Linear read. */static int jedec_read(struct mtd_info *mtd, loff_t from, size_t len, 		      size_t *retlen, u_char *buf){   struct map_info *map = (struct map_info *)mtd->priv;      map->copy_from(map, buf, from, len);   *retlen = len;   return 0;   }/* Banked read. Take special care to jump past the holes in the bank   mapping. This version assumes symetry in the holes.. */static int jedec_read_banked(struct mtd_info *mtd, loff_t from, size_t len, 			     size_t *retlen, u_char *buf){   struct map_info *map = (struct map_info *)mtd->priv;   struct jedec_private *priv = (struct jedec_private *)map->fldrv_priv;   *retlen = 0;   while (len > 0)   {      // Determine what bank and offset into that bank the first byte is      unsigned long bank = from & (~(priv->bank_fill[0]-1));      unsigned long offset = from & (priv->bank_fill[0]-1);      unsigned long get = len;      if (priv->bank_fill[0] - offset < len)	 get = priv->bank_fill[0] - offset;      bank /= priv->bank_fill[0];            map->copy_from(map,buf + *retlen,bank*map->bank_size + offset,get);            len -= get;      *retlen += get;      from += get;   }      return 0;   }/* Pass the flags value that the flash return before it re-entered read    mode. */static void jedec_flash_failed(unsigned char code){   /* Bit 5 being high indicates that there was an internal device      failure, erasure time limits exceeded or something */   if ((code & (1 << 5)) != 0)   {      printk("mtd: Internal Flash failure\n");      return;   }   printk("mtd: Programming didn't take\n");}/* This uses the erasure function described in the AMD Flash Handbook,    it will work for flashes with a fixed sector size only. Flashes with   a selection of sector sizes (ie the AMD Am29F800B) will need a different   routine. This routine tries to parallize erasing multiple chips/sectors    where possible */static int flash_erase(struct mtd_info *mtd, struct erase_info *instr){   // Does IO to the currently selected chip   #define flread(x) map->read8(map,chip->base+((x)<<chip->addrshift))   #define flwrite(v,x) map->write8(map,v,chip->base+((x)<<chip->addrshift))      unsigned long Time = 0;   unsigned long NoTime = 0;   unsigned long start = instr->addr, len = instr->len;   unsigned int I;   struct map_info *map = (struct map_info *)mtd->priv;   struct jedec_private *priv = (struct jedec_private *)map->fldrv_priv;   // Verify the arguments..   if (start + len > mtd->size ||       (start % mtd->erasesize) != 0 ||       (len % mtd->erasesize) != 0 ||       (len/mtd->erasesize) == 0)      return -EINVAL;      jedec_flash_chip_scan(priv,start,len);   // Start the erase sequence on each chip   for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)   {      unsigned long off;      struct jedec_flash_chip *chip = priv->chips + I;            if (chip->length == 0)	 continue;            // Send the erase setup code      xprintf("Erase: ");      puth(chip->start); putc(' ');      puth(chip->base); putc(' ');      puth(chip->length); putc(' ');      puth(chip->sectorsize); putc('\n');            if (chip->start + chip->length > chip->size)      {	 xprintf("DIE\n");	 return -EIO;      }                 flwrite(0xF0,chip->start + 0x555);      flwrite(0xAA,chip->start + 0x555);      flwrite(0x55,chip->start + 0x2AA);      flwrite(0x80,chip->start + 0x555);      flwrite(0xAA,chip->start + 0x555);      flwrite(0x55,chip->start + 0x2AA);      // Use chip erase if possible      if (chip->start == 0 && chip->length == chip->size)      {	 flwrite(0x10,0x555);	 continue;      }                  /* Once we start selecting the erase sectors the delay between each          command must not exceed 50us or it will immediately start erasing          and ignore the other sectors *//*    how do you portably turn off interrupts?      save_flags(flags);      cli();*/      for (off = 0; off < chip->length; off += chip->sectorsize)      {	 // Check to make sure we didn't timeout	 flwrite(0x30,chip->start + off);	 if (off == 0)	    continue;	 if ((flread(chip->start + off) & (1 << 3)) != 0)	 {	    printk("mtd: Ack! We timed out the erase timer!\n");	    return -EIO;	 }       	       }//      restore_flags(flags);   }      /* We could split this into a timer routine and return early, performing      background erasure.. Maybe later if the need warrents */   /* Poll the flash for erasure completion, specs say this can take as long      as 480 seconds to do all the sectors (for a 2 meg flash).       Erasure time is dependant on chip age, temp and wear.. */      /* This being a generic routine assumes a 32 bit bus. It does read32s      and bundles interleved chips into the same grouping. This will work       for all bus widths */   Time = 0;   NoTime = 0;   for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)   {      struct jedec_flash_chip *chip = priv->chips + I;      unsigned long off = 0;      unsigned todo[4] = {0,0,0,0};      unsigned todo_left = 0;      unsigned J;            if (chip->length == 0)	 continue;      /* Find all chips in this data line, realistically this is all          or nothing up to the interleve count */      for (J = 0; priv->chips[J].jedec != 0 && J < MAX_JEDEC_CHIPS; J++)      {	 if ((priv->chips[J].base & (~((1<<chip->addrshift)-1))) == 	     (chip->base & (~((1<<chip->addrshift)-1))))	 {	    todo_left++;	    todo[priv->chips[J].base & ((1<<chip->addrshift)-1)] = 1;	 }	       }      xprintf("todo: %x %x %x %x\n",(short)todo[0],(short)todo[1],	      (short)todo[2],(short)todo[3]);            while (1)      {	 __u32 Last[4];	 unsigned long Count = 0;	 	 /* During erase bit 7 is held low and bit 6 toggles, we watch this,	    should it stop toggling or go high then the erase is completed,  	    or this is not really flash ;> */	 Last[0] = map->read32(map,(chip->base >> chip->addrshift) + chip->start + off);	 Last[1] = map->read32(map,(chip->base >> chip->addrshift) + chip->start + off);	 Last[2] = map->read32(map,(chip->base >> chip->addrshift) + chip->start + off);	 Count = 3;	 while (todo_left != 0)	 {	    for (J = 0; J != 4; J++)	    {	       __u8 Byte1 = (Last[(Count-1)%4] >> (J*8)) & 0xFF;	       __u8 Byte2 = (Last[(Count-2)%4] >> (J*8)) & 0xFF;	       __u8 Byte3 = (Last[(Count-3)%4] >> (J*8)) & 0xFF;	       if (todo[J] == 0)		  continue;	       	       if ((Byte1 & (1 << 7)) == 0 && Byte1 != Byte2)	       {//		  printk("Check %x %x %x\n",(short)J,(short)Byte1,(short)Byte2);		  continue;	       }	       	       if (Byte1 == Byte2)	       {		  jedec_flash_failed(Byte3);		  return -EIO;	       }	       	       todo[J] = 0;	       todo_left--;	    }	    /*	    if (NoTime == 0)	       Time += HZ/10 - schedule_timeout(HZ/10);*/	    NoTime = 0;	    	    Last[Count % 4] = map->read32(map,(chip->base >> chip->addrshift) + chip->start + off);	    Count++;	    	    putc('.');	    /*	    // Count time, max of 15s per sector (according to AMD)	    if (Time > 15*len/mtd->erasesize*HZ)	    {	       printk("mtd: Flash Erase Timed out\n");	       return -EIO;	    }	    */	 }	 	 	 puts("out\n");	    	 // Skip to the next chip if we used chip erase	 if (chip->length == chip->size)	    off = chip->size;	 else	    off += chip->sectorsize;	 	 if (off >= chip->length)	    break;	 NoTime = 1;      }            for (J = 0; priv->chips[J].jedec != 0 && J < MAX_JEDEC_CHIPS; J++)      {	 if ((priv->chips[J].base & (~((1<<chip->addrshift)-1))) ==	     (chip->base & (~((1<<chip->addrshift)-1))))	    priv->chips[J].length = 0;      }         }       	       puts("done\n");   return 0;      #undef flread   #undef flwrite}/* This is the simple flash writing function. It writes to every byte, in   sequence. It takes care of how to properly address the flash if   the flash is interleved. It can only be used if all the chips in the    array are identical!*/static int flash_write(struct mtd_info *mtd, loff_t start, size_t len,		       size_t *retlen, const u_char *buf){   /* Does IO to the currently selected chip. It takes the bank addressing      base (which is divisable by the chip size) adds the necesary lower bits      of addrshift (interleve index) and then adds the control register index. */   #define flread(x) map->read8(map,base+(off&((1<<chip->addrshift)-1))+((x)<<chip->addrshift))   #define flwrite(v,x) map->write8(map,v,base+(off&((1<<chip->addrshift)-1))+((x)<<chip->addrshift))      struct map_info *map = (struct map_info *)mtd->priv;   struct jedec_private *priv = (struct jedec_private *)map->fldrv_priv;   unsigned long base;   unsigned long off;      if (start + len > mtd->size)      return -EIO;      puts("Here");      while (len != 0)   {      struct jedec_flash_chip *chip = priv->chips;      unsigned long bank;      unsigned long boffset;	       // Compute the base of the flash.      off = start % (chip->size << chip->addrshift);      base = start - off;      // Perform banked addressing translation.      bank = base & (~(priv->bank_fill[0]-1));      boffset = base & (priv->bank_fill[0]-1);      bank = (bank/priv->bank_fill[0])*map->bank_size;      base = bank + boffset;            xprintf("Flasing %X %X %X\n",base,chip->size,len);            // Loop over this page      for (; off != (chip->size << chip->addrshift) && len != 0; start++, len--, off++,buf++)      {	 unsigned char oldbyte = map->read8(map,base+off);	 unsigned char Last[4];	 unsigned long Count = 0;//	 putc('.');	 	 if (oldbyte == *buf)	    continue;	 if (((~oldbyte) & *buf) != 0)	    printk("mtd: warn: Trying to set a 0 to a 1\n");	     	 // Write	 flwrite(0xAA,0x555);	 flwrite(0x55,0x2AA);	 flwrite(0xA0,0x555);	 map->write8(map,*buf,base + off);	 Last[0] = map->read8(map,base + off);	 Last[1] = map->read8(map,base + off);	 Last[2] = map->read8(map,base + off);	 	 /* Wait for the flash to finish the operation. We store the last 4	    status bytes that have been retrieved so we can determine why	    it failed. The toggle bits keep toggling when there is a 	    failure */	 for (Count = 3; Last[(Count - 1) % 4] != Last[(Count - 2) % 4] &&	      Count < 10000; Count++)	    Last[Count % 4] = map->read8(map,base + off);	 if (Last[(Count - 1) % 4] != *buf)	 {	    jedec_flash_failed(Last[(Count - 3) % 4]);	    return -EIO;	 }	       }   }   *retlen = len;   return 0;}/* This is used to enhance the speed of the erase routine,   when things are being done to multiple chips it is possible to   parallize the operations, particularly full memory erases of multi   chip memories benifit */static void jedec_flash_chip_scan(struct jedec_private *priv,unsigned long start,		     unsigned long len){   unsigned int I;   // Zero the records   for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)      priv->chips[I].start = priv->chips[I].length = 0;      // Intersect the region with each chip   for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)   {      struct jedec_flash_chip *chip = priv->chips + I;      unsigned long ByteStart;      unsigned long ChipEndByte = chip->offset + (chip->size << chip->addrshift);            // End is before this chip or the start is after it      if (start+len < chip->offset ||	  ChipEndByte - (1 << chip->addrshift) < start)	 continue;            if (start < chip->offset)      {	 ByteStart = chip->offset;	 chip->start = 0;      }            else      {	 chip->start = (start - chip->offset + (1 << chip->addrshift)-1) >> chip->addrshift;	 ByteStart = start;      }      if (start + len >= ChipEndByte)	 chip->length = (ChipEndByte - ByteStart) >> chip->addrshift;      else	 chip->length = (start + len - ByteStart + (1 << chip->addrshift)-1) >> chip->addrshift;   }}									/*}}}*/

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -