📄 flash.c
字号:
wlen = flash_safe_write(part, (unsigned char *)part->start + filp->f_pos, (unsigned char *)buf, count); /* advance file position pointer */ if(wlen >= 0) filp->f_pos += wlen; return wlen;}#endif /* CONFIG_CHR_DEV_FLASH */static intflash_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ int minor; struct flashpartition *part; struct flashchipinfo *finfo; if (!inode || !inode->i_rdev) return -EINVAL; minor = MINOR(inode->i_rdev); if(minor < FLASH_MINOR) return -EINVAL; /* only ioctl's for flash devices */ part = &partitions[minor - FLASH_MINOR]; switch(cmd) { case FLASHIO_CHIPINFO: if(!suser()) return -EACCES; if(arg == 0) return -EINVAL; finfo = (struct flashchipinfo *)arg; /* TODO: verify arg */ finfo->isValid = chips[0].isValid; finfo->manufacturer_id = chips[0].manufacturer_id; finfo->device_id = chips[0].device_id; finfo->size = chips[0].size; finfo->sectorsize = chips[0].sectorsize; return 0; case FLASHIO_ERASEALL: if(!part->start) return -EINVAL; if(!suser()) return -EACCES; /* Invalidate all pages and buffers */ invalidate_inodes(inode->i_rdev); invalidate_buffers(inode->i_rdev); /* * Start the erasure, then sleep and wake up now and * then to see if it's done. We use the waitqueue to * make sure we don't start erasing in the middle of * a write, or that nobody start using the flash while * we're erasing. * * TODO: break up partition erases that spans more than one * chip. */ flash_safe_acquire(part); flash_init_erase(part->start, part->size); while (flash_is_busy(part->start) || !flash_pos_is_clean(part->start)) { current->state = TASK_INTERRUPTIBLE; current->timeout = jiffies + HZ / 2; schedule(); } flash_safe_release(part); return 0; default: return -EPERM; } return -EPERM;}/* probe for Flash RAM's - this isn't in the init function, because this needs * to be done really early in the boot, so we can use the device to burn an * image before the system is running. */voidflash_probe(){ int i; /* start adresses for the Flash chips - these should really * be settable in some other way. */#ifdef FLASH_VERBOSE safe_printk("Probing flash...\n");#endif#ifdef CONFIG_COLDFIRE chips[0].start = (unsigned char *)(0xf0110000);#else chips[0].start = (unsigned char *)(MEM_CSE0_START | MEM_NON_CACHEABLE); chips[1].start = (unsigned char *)(MEM_CSE1_START | MEM_NON_CACHEABLE);#endif for(i = 0; i < MAX_CHIPS; i++) { struct flashchip *chip = chips + i; flashptr flashStart = (flashptr)chip->start; unsigned short manu;#ifdef FLASH_VERBOSE FDEBUG(safe_printk("Probing flash #%d at 0x%x\n", i, flashStart));#endif#ifdef CONFIG_SVINTO_SIM /* in the simulator, dont trash the flash ram by writing unlocks */ chip->isValid = 1; chip->device_id = AM29LV160BT;#else /* reset */ flashStart[unlockAddress1] = unlockData1; flashStart[unlockAddress2] = unlockData2; flashStart[unlockAddress1] = resetData; /* read manufacturer */ flashStart[unlockAddress1] = unlockData1; flashStart[unlockAddress2] = unlockData2; flashStart[unlockAddress1] = manufacturerUnlockData; flashStart[unlockAddress1] = 0x9898; manu = flashStart[manufacturerAddress]; chip->isValid = (manu == ManufacturerAMD || manu == ManufacturerToshiba || manu == ManufacturerST || manu == ManufacturerSST); chip->manufacturer_id = manu; /* reset */ flashStart[unlockAddress1] = unlockData1; flashStart[unlockAddress2] = unlockData2; flashStart[unlockAddress1] = resetData; /* read device id */ flashStart[unlockAddress1] = unlockData1; flashStart[unlockAddress2] = unlockData2; flashStart[unlockAddress1] = manufacturerUnlockData; chip->device_id = flashStart[deviceIdAddress]; /* reset */ flashStart[unlockAddress1] = unlockData1; flashStart[unlockAddress2] = unlockData2; flashStart[unlockAddress1] = resetData;#endif /* check device type and fill in correct sizes etc */ switch(chip->device_id) { case AM29LV160BT: case TC58FVT160:#ifdef FLASH_VERBOSE safe_printk("Flash: 16Mb TB\n");#endif chip->size = 0x00200000; chip->sectorsize = 0x10000; chip->bootsector = chip->start + chip->size - chip->sectorsize; chip->bootsectorsize[0] = 0x8000; chip->bootsectorsize[1] = 0x2000; chip->bootsectorsize[2] = 0x2000; chip->bootsectorsize[3] = 0x4000; break; //case AM29LV160BB: case TC58FVB160:#ifdef FLASH_VERBOSE safe_printk("Flash: 16Mb BB\n");#endif chip->size = 0x00200000; chip->sectorsize = 0x10000; chip->bootsector = chip->start; chip->bootsectorsize[0] = 0x4000; chip->bootsectorsize[1] = 0x2000; chip->bootsectorsize[2] = 0x2000; chip->bootsectorsize[3] = 0x8000; break; case AM29LV800BB: case AM29F800BB:#ifdef FLASH_VERBOSE safe_printk("Flash: 8Mb BB\n");#endif chip->size = 0x00100000; chip->sectorsize = 0x10000; chip->bootsector = chip->start; chip->bootsectorsize[0] = 0x4000; chip->bootsectorsize[1] = 0x2000; chip->bootsectorsize[2] = 0x2000; chip->bootsectorsize[3] = 0x8000; break; case M29W800T: case AM29LV800BT: case AM29F800BT:#ifdef FLASH_VERBOSE safe_printk("Flash: 8Mb TB\n");#endif chip->size = 0x00100000; chip->sectorsize = 0x10000; chip->bootsector = chip->start + chip->size - chip->sectorsize; chip->bootsectorsize[0] = 0x8000; chip->bootsectorsize[1] = 0x2000; chip->bootsectorsize[2] = 0x2000; chip->bootsectorsize[3] = 0x4000; break; // case AM29LV800BB: /* the following supports smaller sector erases (like 2 Kword) * so they dont use bootblocks. until we've implemented real * support for the smaller erases, we just treat them as if they * dont have bootblocks at all. */ case SST39LF800:#ifdef FLASH_VERBOSE safe_printk("Flash: 8Mb No B\n");#endif chip->size = 0x00010000; chip->sectorsize = 0x1000; chip->bootsector = (unsigned char *)MEM_DRAM_START; /* never a flash address (see above) */ break; case SST39VF160:#ifdef FLASH_VERBOSE safe_printk("Flash: SST39VF160 16Mb No B");#endif chip->size = 0x00100000; chip->sectorsize = 0x0100; chip->bootsector = (unsigned char *)MEM_DRAM_START; /* never a flash address */ break; default:#ifdef FLASH_VERBOSE safe_printk("Flash: Unknown device\n");#endif chip->isValid = 1; chip->size = 0x00100000; chip->sectorsize = 0x1000; chip->bootsector = (unsigned char *)MEM_DRAM_START; break; } chip->busy = 0; init_waitqueue(&chip->wqueue); }}/* locate the flashchip structure associated with the given adress */static struct flashchip *getchip(unsigned char *ptr){ int i; for (i = 0; i < MAX_CHIPS; i++) { FDEBUG(printk("flash: chips[i].start: 0x%x,chips[i].size=0x%x!\n", chips[i].start,chips[i].size)); if (ptr >= chips[i].start && ptr < (chips[i].start + chips[i].size)) { return &chips[i]; } } printk("flash: Illegal address: getchip(0x%p)!\n", ptr); return (void *)0;}void *flash_getpart(kdev_t dev){ struct flashpartition *part; if (MINOR(dev) < FLASH_MINOR) { return 0; } part = &partitions[MINOR(dev) - FLASH_MINOR]; if (!part->start) { return 0; } return (void *)part;}unsigned char *flash_get_direct_pointer(kdev_t dev, __u32 offset){ struct flashpartition *part; if (MINOR(dev) < FLASH_MINOR) { return 0; } part = &partitions[MINOR(dev) - FLASH_MINOR]; if (!part->start) { return 0; } return (unsigned char *) ((__u32) part->start + offset);}/* start erasing flash-memory at ptr of a certain size * this does not wait until the erasing is done */voidflash_init_erase(unsigned char *ptr, unsigned int size){ struct flashchip *chip; int bootSectorCounter = 0; unsigned int erasedSize = 0; flashptr flashStart; unsigned long i; unsigned short status;#ifdef IRQ_LOCKS unsigned long flags;#endif ptr = (unsigned char *)((unsigned long)ptr | MEM_NON_CACHEABLE); chip = getchip(ptr); flashStart = (flashptr)chip->start; FDEBUG(safe_printk("Flash: erasing memory at 0x%p, size 0x%x.\n", ptr, size)); /* need to disable interrupts, to avoid possible delays between the * unlocking and erase-init */#ifdef IRQ_LOCKS save_flags(flags); cli();#endif /* Init erasing of the number of sectors needed */ printk("Erase flash device now,please wait...\n"); while (erasedSize < size) { flashStart[unlockAddress1] = unlockData1; flashStart[unlockAddress2] = unlockData2; flashStart[unlockAddress1] = sectorEraseUnlockData; flashStart[unlockAddress1] = unlockData1; flashStart[unlockAddress2] = unlockData2; *(flashptr)ptr = sectorEraseUnlockData2; /* make sure we erase the individual bootsectors if in that area */ /* TODO this BREAKS if we start erasing in the middle of the bootblock! */ if (ptr < chip->bootsector || ptr >= (chip->bootsector + chip->sectorsize)) { erasedSize += chip->sectorsize; ptr += chip->sectorsize; } else { erasedSize += chip->bootsectorsize[bootSectorCounter]; ptr += chip->bootsectorsize[bootSectorCounter++]; } for(i=0;i<0x30000;i++){ status=*(flashptr)ptr; if(status&0x0080){ FDEBUG(printk("Erase address 0x%x OK! i=%d\n",ptr,i)); break; } } } printk("Erased OK! You can mount jffs now!\n");#ifdef IRQ_LOCKS restore_flags(flags);#endif /* give the busy signal time enough to activate (tBusy, 90 ns) */ nop(); nop(); nop(); nop(); nop(); nop(); nop(); nop(); nop();}intflash_erase_region(kdev_t dev, __u32 offset, __u32 size){ int minor; struct flashpartition *part; unsigned char *erase_start; short retries = 5; short success; minor = MINOR(dev); if (minor < FLASH_MINOR) { return -EINVAL; } part = &partitions[minor - FLASH_MINOR]; if (!part->start) { return -EINVAL; } /* Start the erasure, then sleep and wake up now and then to see * if it's done. */ erase_start = part->start + offset; flash_safe_acquire(part); do { flash_init_erase(erase_start, size); while (flash_is_busy(erase_start)) { current->state = TASK_INTERRUPTIBLE; current->timeout = jiffies + HZ / 2; schedule(); } success = ((flashptr)erase_start)[0] == 0xffff && ((flashptr)erase_start)[1] == 0xffff && ((flashptr)erase_start)[2] == 0xffff && ((flashptr)erase_start)[3] == 0xffff; if (!success) { printk(KERN_NOTICE "flash: erase of region " "[0x%p, 0x%p] failed once\n", erase_start, erase_start + size); } } while (retries-- && !success); flash_safe_release(part); if (retries == 0 && !success) { printk(KERN_WARNING "flash: erase of region " "[0x%p, 0x%p] totally failed\n", erase_start, erase_start + size); return -1; } return 0;}/* wait until the erase operation is finished, in a CPU hogging manner */voidflash_busy_wait_erase(unsigned char *ptr){ flashptr flashStart; ptr = (unsigned char *)((unsigned long)ptr | MEM_NON_CACHEABLE); flashStart = (flashptr)getchip(ptr)->start; /* busy-wait for flash completion - when D6 stops toggling between * reads. */ while (flash_is_busy(flashStart)) /* nothing */;}/* erase all flashchips and wait until operation is completed */voidflash_erase_all(){ /* TODO: we should loop over chips, not just try the first two! */ if(chips[0].isValid) flash_init_erase(chips[0].start, chips[0].size); if(chips[1].isValid) flash_init_erase(chips[1].start, chips[0].size); if(chips[0].isValid) flash_busy_wait_erase(chips[0].start); if(chips[1].isValid) flash_busy_wait_erase(chips[1].start);#ifdef FLASH_VERBOSE safe_printk("Flash: full erasure completed.\n");#endif}/* Write a block of Flash. The destination Flash sectors need to be erased * first. If the size is larger than the Flash chip the block starts in, the * function will continue flashing in the next chip if it exists. * Returns 0 on success, -1 on error. */intflash_write(unsigned char *ptr, const unsigned char *source, unsigned int size){#ifndef CONFIG_SVINTO_SIM struct flashchip *chip; flashptr theData = (flashptr)source; flashptr flashStart; flashptr programAddress; int i, fsize; int odd_size; ptr = (unsigned char *)((unsigned long)ptr | MEM_NON_CACHEABLE); while(size > 0) { chip = getchip(ptr);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -