📄 blkmem.c
字号:
/* * FLASH programming routine for the 29LVX00 device family. */static void flash_amd8_write(struct arena_t * a, unsigned long pos, unsigned long length, char * buffer){ volatile unsigned char *address; unsigned long flags, fbase = a->address; unsigned char *wbuf, status; int i; #if 0 printk("%s(%d): flash_amd8_write(a=%x,pos=%x,length=%d,buf=%x)\n", __FILE__, __LINE__, (int) a, (int) pos, (int) length, (int) buffer);#endif down(&spare_lock);#if defined(CONFIG_WATCHDOG) watchdog_disable();#endif address = (unsigned volatile char *) (fbase + pos); wbuf = (unsigned char *) buffer; for (; (length > 0); length--, address++, wbuf++) { if (*address != *wbuf) { save_flags(flags); cli(); *((volatile unsigned char *) (fbase | 0xaaa)) = 0xaa; *((volatile unsigned char *) (fbase | 0x555)) = 0x55; *((volatile unsigned char *) (fbase | 0xaaa)) = 0xa0; *address = *wbuf; for (i = 0; (i < FTIMEOUT); i++) { status = *address; if (status == *wbuf) { /* Program complete */ break; } } if (*address != *wbuf) { printk("%s(%d): FLASH write failed i=%d, address %p -> %x(%x)\n", __FILE__, __LINE__, i, address, *wbuf, *address); *((unsigned volatile char *) fbase) = 0xf0; /* Reset */ } restore_flags(flags); } }#if defined(CONFIG_WATCHDOG) watchdog_enable();#endif up(&spare_lock);}/* * Program a complete FLASH image. This runs from DRAM, so no * need to worry about writing to what we are running from... */static void flash_amd8_writeall(struct arena_t * a, struct blkmem_program_t * prog){ unsigned long base, offset, erased; unsigned long ptr, min, max; unsigned char *w, status; int failures; int i, j, l;#if defined(CONFIG_WATCHDOG) watchdog_disable();#endif #if 0 printk("FLASH: programming");#endif failures = 0; erased = 0; cli(); for (i = 0; (i < prog->blocks); i++) {#if 0 printk("%s(%d): block=%d address=%x pos=%x length=%x range=%x-%x\n", __FILE__, __LINE__, i, (int) a->address, (int) prog->block[i].pos, (int) prog->block[i].length, (int) (prog->block[i].pos + a->address), (int) (prog->block[i].pos + prog->block[i].length - 1 + a->address));#endif /* * Erase FLASH sectors for this program block... */ for (l = prog->block[i].pos / a->blksize; l <= ((prog->block[i].pos+prog->block[i].length-1) / a->blksize); l++) { if (erased & (0x1 << l)) continue; ptr = l * a->blksize; offset = ptr % a->unitsize; base = ptr - offset; base += a->address; ptr += a->address; j = 0;flash_redo:#if 0 printk("%s(%d): ERASE BLOCK sector=%d base=%x offset=%x ptr=%x\n", __FILE__, __LINE__, l, (int) base, (int) offset, (int) ptr);#endif /* Erase this sector */ *((volatile unsigned char *) (base | 0xaaa)) = 0xaa; *((volatile unsigned char *) (base | 0x555)) = 0x55; *((volatile unsigned char *) (base | 0xaaa)) = 0x80; *((volatile unsigned char *) (base | 0xaaa)) = 0xaa; *((volatile unsigned char *) (base | 0x555)) = 0x55; *((volatile unsigned char *) ptr) = 0x30; for (;;) { status = *((volatile unsigned char *) ptr); if (status & 0x80) { /* Erase complete */ break; } if (status & 0x20) { printk("FLASH: (%d) erase failed\n", __LINE__); /* Reset FLASH unit */ *((volatile unsigned char *) base) = 0xf0; failures++; /* Continue (with unerased sector) */ break; } } /* * Some flash have a set of small segments at the top or bottom. * These need to be erased individually, even better, different * devices uses different segment sizes :-( * This code currently only handles bottom booters... */ if ((ptr & FLASHMASK) < 64*1024) { ptr += flash_bootsegs[j++]; if ((ptr - base) < a->length) goto flash_redo; } erased |= (0x1 << l); } /* * Program FLASH with the block data... */ min = prog->block[i].pos+a->address; max = prog->block[i].pos+prog->block[i].length+a->address; w = (unsigned char *) prog->block[i].data; /* Progress indicators... */ printk(".");#ifdef CONFIG_LEDMAN if (i & 1) { ledman_cmd(LEDMAN_CMD_OFF, LEDMAN_NVRAM_1); ledman_cmd(LEDMAN_CMD_ON, LEDMAN_NVRAM_2); } else { ledman_cmd(LEDMAN_CMD_ON, LEDMAN_NVRAM_1); ledman_cmd(LEDMAN_CMD_OFF, LEDMAN_NVRAM_2); }#endif#if 0 printk("%s(%d): PROGRAM BLOCK min=%x max=%x\n", __FILE__, __LINE__, (int) min, (int) max);#endif for (ptr = min; (ptr < max); ptr++, w++) { offset = (ptr - a->address) % a->unitsize; base = ptr - offset;#if 0 printk("%s(%d): PROGRAM base=%x offset=%x ptr=%x value=%x\n", __FILE__, __LINE__, (int) base, (int) offset, (int) ptr, (int) *w);#endif *((volatile unsigned char *) (base | 0xaaa)) = 0xaa; *((volatile unsigned char *) (base | 0x555)) = 0x55; *((volatile unsigned char *) (base | 0xaaa)) = 0xa0; *((volatile unsigned char *) ptr) = *w; for (j = 0; (j < FTIMEOUT); j++) { status = *((volatile unsigned char *) ptr); if (status == *w) { /* Program complete */ break; } } status = *((volatile unsigned char *) ptr); if (status != *w) { printk("FLASH: (%d) write failed, addr=%x val=%x status=%x cnt=%d\n", __LINE__, (int) ptr, *w, status, j); /* Reset FLASH unit */ *((volatile unsigned char *) ptr) = 0xf0; failures++; } } }#ifdef CONFIG_LEDMAN ledman_cmd(LEDMAN_CMD_RESET, LEDMAN_NVRAM_1); ledman_cmd(LEDMAN_CMD_RESET, LEDMAN_NVRAM_2);#endif if (failures > 0) { printk("FLASH: %d failures programming FLASH!\n", failures); return; }#if 0 printk("\nFLASH: programming successful!\n");#endif if (prog->reset) { printk("FLASH: rebooting...\n\n"); HARD_RESET_NOW(); }}/****************************************************************************//* AMD 16bit FLASH *//****************************************************************************/#else/* * FLASH erase routine for the AMD 29LVxxx family devices. */static void flash_amd16_erase(struct arena_t *a, unsigned long pos){ unsigned volatile short *address; unsigned long fbase = a->address; unsigned long flags; unsigned short status; int i; #if 0 printk("%s(%d): flash_amd16_erase(a=%x,pos=%x)\n", __FILE__, __LINE__, (int) a, (int) pos);#endif if (pos >= a->length) return; address = (unsigned volatile short *) (fbase + pos); /* Mutex all access to FLASH memory */ down(&spare_lock); save_flags(flags); cli();#if defined(CONFIG_WATCHDOG) watchdog_disable();#endif /* Erase this sector */ *((volatile unsigned short *) (fbase | (0x555 << 1))) = 0xaaaa; *((volatile unsigned short *) (fbase | (0x2aa << 1))) = 0x5555; *((volatile unsigned short *) (fbase | (0x555 << 1))) = 0x8080; *((volatile unsigned short *) (fbase | (0x555 << 1))) = 0xaaaa; *((volatile unsigned short *) (fbase | (0x2aa << 1))) = 0x5555; *address = 0x3030; for (i = 0; (i < FTIMEOUT); i++) { status = *address; if ((status & 0x0080) || (status & 0x0020)) break; } if (*address != 0xffff) { printk("%s(%d): FLASH erase failed, address %p iteration=%d status=%x\n", __FILE__, __LINE__, address, i, status); *((unsigned volatile short *) fbase) = 0xf0f0; /* Reset */ }#if defined(CONFIG_WATCHDOG) watchdog_enable();#endif restore_flags(flags); up(&spare_lock);}/* * FLASH programming routine for the 29LVxxx device family. */static void flash_amd16_write(struct arena_t * a, unsigned long pos, unsigned long length, char * buffer){ volatile unsigned short *address; unsigned long flags, fbase = a->address; unsigned short *wbuf, status; int i; #if 0 printk("%s(%d): flash_amd16_write(a=%x,pos=%x,length=%d,buf=%x)\n", __FILE__, __LINE__, (int) a, (int) pos, (int) length, (int) buffer);#endif down(&spare_lock);#if defined(CONFIG_WATCHDOG) watchdog_disable();#endif address = (unsigned volatile short *) (fbase + pos); wbuf = (unsigned short *) buffer; length += 1; /* Fix it so that an odd number of bytes gets written correctly */ for (length >>= 1; (length > 0); length--, address++, wbuf++) { if (*address != *wbuf) { save_flags(flags); cli(); *((volatile unsigned short *) (fbase | (0x555 << 1))) = 0xaaaa; *((volatile unsigned short *) (fbase | (0x2aa << 1))) = 0x5555; *((volatile unsigned short *) (fbase | (0x555 << 1))) = 0xa0a0; *address = *wbuf; for (i = 0; (i < FTIMEOUT); i++) { status = *address; if (status == *wbuf) { /* Program complete */ break; } } if (*address != *wbuf) { printk("%s(%d): FLASH write failed i=%d, address %p -> %x(%x)\n", __FILE__, __LINE__, i, address, *wbuf, *address); *((unsigned volatile short *) fbase) = 0xf0f0; /* Reset */ } restore_flags(flags); } }#if defined(CONFIG_WATCHDOG) watchdog_enable();#endif up(&spare_lock);}/* * Program a complete FLASH image. This runs from DRAM, so no * need to worry about writing to what we are running from... */static void flash_amd16_writeall(struct arena_t * a, struct blkmem_program_t * prog){ unsigned long base, offset, erased; unsigned long ptr, min, max; unsigned short *w, status; int failures; int i, j, l;#if defined(CONFIG_WATCHDOG) watchdog_disable();#endif #if 0 printk("FLASH: programming");#endif failures = 0; erased = 0; cli(); for (i = 0; (i < prog->blocks); i++) {#if 0 printk("%s(%d): block=%d address=%x pos=%x length=%x range=%x-%x\n", __FILE__, __LINE__, i, (int) a->address, (int) prog->block[i].pos, (int) prog->block[i].length, (int) (prog->block[i].pos + a->address), (int) (prog->block[i].pos + prog->block[i].length - 1 + a->address));#endif /* * Erase FLASH sectors for this program block... */ for (l = prog->block[i].pos / a->blksize; l <= ((prog->block[i].pos+prog->block[i].length-1) / a->blksize); l++) { if (erased & (0x1 << l)) continue; ptr = l * a->blksize; offset = ptr % a->unitsize; base = ptr - offset; base += a->address; ptr += a->address; j = 0;flash_redo:#if 0 printk("%s(%d): ERASE BLOCK sector=%d base=%x offset=%x ptr=%x\n", __FILE__, __LINE__, l, (int) base, (int) offset, (int) ptr);#endif /* Erase this sector */ /* FIX: check which byte lane the value needs to be on */ *((volatile unsigned short *) (base | (0x555 << 1))) = 0xaaaa; *((volatile unsigned short *) (base | (0x2aa << 1))) = 0x5555; *((volatile unsigned short *) (base | (0x555 << 1))) = 0x8080; *((volatile unsigned short *) (base | (0x555 << 1))) = 0xaaaa; *((volatile unsigned short *) (base | (0x2aa << 1))) = 0x5555; *((volatile unsigned short *) ptr) = 0x3030; for (;;) { status = *((volatile unsigned short *) ptr); if (status & 0x0080) { /* Erase complete */ break; } if (status & 0x0020) { printk("FLASH: (%d) erase failed\n", __LINE__); /* Reset FLASH unit */ *((volatile unsigned short *) base) = 0xf0f0; failures++; /* Continue (with unerased sector) */ break; } } /* * Some flash have a set of small segments at the top or bottom. * These need to be erased individually, even better, different * devices uses different segment sizes :-( * This code currently only handles bottom booters... */ if ((ptr & FLASHMASK) < 64*1024) { ptr += flash_bootsegs[j++]; if ((ptr - base) < a->length) goto flash_redo; } erased |= (0x1 << l); } /* * Program FLASH with the block data... */ min = prog->block[i].pos+a->address; max = prog->block[i].pos+prog->block[i].length+a->address; w = (unsigned short *) prog->block[i].data; /* Progress indicators... */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -