📄 flash.c
字号:
#include "types.h"#include "bios.h"#include "flash.h"#include "console.h"#include "utils.h"const struct flash_info table[] = { { mfr_id: MANUFACTURER_AMD, dev_id: AM29F040B, name: "AM29F040B", size: 0x00080000, numeraseregions: 1, regions: { { offset: 0x000000, erasesize: 0x10000, numblocks: 8} } }, { mfr_id: MANUFACTURER_AMD, dev_id: AM29LV040B, name: "AM29LV040B", size: 0x00080000, numeraseregions: 1, regions: { { offset: 0x000000, erasesize: 0x10000, numblocks: 8} } }, { mfr_id: MANUFACTURER_AMD, dev_id: AM29LV160BT_DT, name: "AM29LV160BT/DT", size: 0x00200000, numeraseregions: 4, regions: { { offset: 0x000000, erasesize: 0x10000, numblocks: 31 }, { offset: 0x1F0000, erasesize: 0x08000, numblocks: 1 }, { offset: 0x1F8000, erasesize: 0x02000, numblocks: 2 }, { offset: 0x1FC000, erasesize: 0x04000, numblocks: 1 } } }, { mfr_id: MANUFACTURER_AMD, dev_id: AM29LV160BB_DB, name: "AM29LV160BB/DB", size: 0x00200000, numeraseregions: 4, regions: { { offset: 0x000000, erasesize: 0x04000, numblocks: 1 }, { offset: 0x004000, erasesize: 0x02000, numblocks: 2 }, { offset: 0x008000, erasesize: 0x08000, numblocks: 1 }, { offset: 0x010000, erasesize: 0x10000, numblocks: 31 } } }, { mfr_id: MANUFACTURER_HYNIX, dev_id: HY29F040A, name: "HY29F040A", size: 0x00200000, numeraseregions: 1, regions: { { offset: 0x000000, erasesize: 0x10000, numblocks: 8} } }, { mfr_id: MANUFACTURER_HYNIX, dev_id: HY29LV160T, name: "HY29LV160T", size: 0x00200000, numeraseregions: 4, regions: { { offset: 0x000000, erasesize: 0x10000, numblocks: 31 }, { offset: 0x1F0000, erasesize: 0x08000, numblocks: 1 }, { offset: 0x1F8000, erasesize: 0x02000, numblocks: 2 }, { offset: 0x1FC000, erasesize: 0x04000, numblocks: 1 } } }, { mfr_id: MANUFACTURER_HYNIX, dev_id: HY29LV160B, name: "HY29LV160B", size: 0x00200000, numeraseregions: 4, regions: { { offset: 0x000000, erasesize: 0x04000, numblocks: 1 }, { offset: 0x004000, erasesize: 0x02000, numblocks: 2 }, { offset: 0x008000, erasesize: 0x08000, numblocks: 1 }, { offset: 0x010000, erasesize: 0x10000, numblocks: 31 } } }, { mfr_id: MANUFACTURER_SST, dev_id: SST39VF040, name: "SST39VF040", size: 0x00080000, numeraseregions: 1, regions: { { offset: 0x000000, erasesize: 0x01000, numblocks: 128 } } }, { mfr_id: MANUFACTURER_SST, dev_id: SST39VF080, name: "SST39VF080", size: 0x00100000, numeraseregions: 1, regions: { { offset: 0x000000, erasesize: 0x01000, numblocks: 256 } } }, { mfr_id: MANUFACTURER_SST, dev_id: SST39VF016, name: "SST39VF016", size: 0x00200000, numeraseregions: 1, regions: { { offset: 0x000000, erasesize: 0x01000, numblocks: 512 } } }};struct mtd_info mtd;static unsigned long wide_read(struct flchip *chip, unsigned long addr){ unsigned long mem_addr; mem_addr = chip->mtd->offset + chip->start + addr; mem_addr |= NOCACHE_BIT; switch (chip->buswidth) { case 1: return *((unsigned char *)mem_addr); case 2: return *((unsigned short *)mem_addr); case 4: return *((unsigned long *)mem_addr); default: printf("wide_read(): unsupported buswidth\r\n"); } return 0;}static void wide_write(struct flchip *chip, unsigned long val, unsigned long addr){ unsigned long mem_addr; mem_addr = chip->mtd->offset + chip->start + addr; mem_addr |= NOCACHE_BIT; switch (chip->buswidth) { case 1: *((unsigned char *)mem_addr) = val; break; case 2: *((unsigned short *)mem_addr) = val; break; case 4: *((unsigned long *)mem_addr) = val; break; default: printf("wide_write(): unsupported buswidth\r\n"); break; }}static unsigned long make_cmd(struct flchip *chip, unsigned long cmd){ return cmd;}static void send_unlock(struct flchip *chip){ wide_write(chip, make_cmd(chip, CMD_UNLOCK_DATA_1), chip->buswidth * ADDR_UNLOCK_1); wide_write(chip, make_cmd(chip, CMD_UNLOCK_DATA_2), chip->buswidth * ADDR_UNLOCK_2);}static void send_cmd(struct flchip *chip, unsigned long cmd){ send_unlock(chip); wide_write(chip, make_cmd(chip, cmd), chip->buswidth * ADDR_UNLOCK_1);}static void send_cmd_to_addr(struct flchip *chip, unsigned long cmd, unsigned long addr){ send_unlock(chip); wide_write(chip, make_cmd(chip, cmd), addr);}static int probe_chip(struct mtd_info *mtd, unsigned long base, struct flchip *chip){ unsigned long mfr_id; unsigned long dev_id; int buswidth; int table_size = sizeof(table) / sizeof(table[0]); int i; chip->mtd = mtd; chip->start = base; for (buswidth = 1; buswidth <= 4; buswidth <<= 1) { chip->buswidth = buswidth; /* Enter autoselect mode. */ send_cmd(chip, CMD_RESET_DATA); send_cmd(chip, CMD_MANUFACTURER_UNLOCK_DATA); mfr_id = wide_read(chip, chip->buswidth * ADDR_MANUFACTURER); dev_id = wide_read(chip, chip->buswidth * ADDR_DEVICE_ID); /* Exit autoselect mode. */ send_cmd(chip, CMD_RESET_DATA); for (i = 0; i < table_size; i++) { if ((mfr_id == table[i].mfr_id) && (dev_id == table[i].dev_id)) { chip->size = table[i].size; chip->numeraseregions = table[i].numeraseregions; memcpy(chip->regions, table[i].regions, sizeof(chip->regions)); printf("Found "); printf(table[i].name); printf(" at 0x%08lx\r\n", base); return 0; } } } return -1;}static int chip_is_busy(struct flchip *chip, unsigned long addr){ return ((wide_read(chip, addr) & D6_MASK) != (wide_read(chip, addr) & D6_MASK));}static int erase_one_block(struct flchip *chip, unsigned long addr, unsigned long size){ int times_left; send_cmd(chip, CMD_SECTOR_ERASE_UNLOCK_DATA); send_cmd_to_addr(chip, CMD_SECTOR_ERASE_UNLOCK_DATA_2, addr); times_left = 500000; while (times_left-- && chip_is_busy(chip, addr)); if (!times_left) return -1; return 0;}static int flash_erase_internal(struct mtd_info *mtd, unsigned long addr, unsigned long size){ struct flchip *chip; struct erase_region *region; int chip_start, chip_end; int region_start, region_end; int i, j, n; for (i = 0; i < mtd->numchips; i++) { chip = &mtd->chips[i]; chip_start = chip->start; chip_end = chip->start + chip->size; if ((addr >= chip_end) || (addr + size <= chip_start)) continue; if (chip_start < addr) chip_start = addr; if (chip_end > addr + size) chip_end = addr + size; for (j = 0; j < chip->numeraseregions; j++) { region = &chip->regions[j]; region_start = chip->start + region->offset; region_end = region_start + (region->erasesize * region->numblocks); if ((chip_start >= region_end) || (chip_end <= region_start)) continue; if (region_start < chip_start) region_start = chip_start; if (region_end > chip_end) region_end = chip_end; for (n = region_start; n < region_end; n += region->erasesize) erase_one_block(chip, n - chip->start, region->erasesize); } } return 0;}static int flash_read_internal(struct mtd_info *mtd, unsigned long from, unsigned long len, unsigned long *retlen, unsigned char *buf){ if ((from + len) > mtd->size) return -1; memcpy(buf, (char *)((mtd->offset + from) | NOCACHE_BIT), len); *retlen = len; return 0;}static int write_one_word(struct mtd_info *mtd, struct flchip *chip, unsigned long addr, unsigned long datum){ int times_left; send_cmd(chip, CMD_PROGRAM_UNLOCK_DATA); wide_write(chip, datum, addr); times_left = 500000; while (times_left-- && chip_is_busy(chip, addr)); if (!times_left) return -1; return 0;}static int flash_write_internal(struct mtd_info *mtd, unsigned long to, unsigned long len, unsigned long *retlen, const unsigned char *buf){ struct flchip *chip; int chip_start, chip_end; int i, n; *retlen = 0; for (i = 0; i < mtd->numchips; i++) { chip = &mtd->chips[i]; chip_start = chip->start; chip_end = chip->start + chip->size; if ((to >= chip_end) || (to + len <= chip_start)) continue; if (chip_start < to) chip_start = to; if (chip_end > to + len) chip_end = to + len; if (chip->buswidth == 1) for (n = chip_start; n < chip_end; n++) write_one_word(mtd, chip, n - chip->start, buf[n - to]); else if (chip->buswidth == 2) for (n = chip_start; n < chip_end; n += 2) write_one_word(mtd, chip, n - chip->start, *((unsigned short *)(&buf[n - to]))); else if (chip->buswidth == 4) for (n = chip_start; n < chip_end; n += 4) write_one_word(mtd, chip, n - chip->start, *((unsigned long *)(&buf[n - to]))); else { printf("flash_write_internal(): unsupported buswidth\r\n"); return -1; } *retlen += chip_end - chip_start; } return 0;}int flash_init(unsigned long rom_base){ unsigned long flash_base; struct flchip *chip; int i; mtd.offset = rom_base; mtd.size = 0; mtd.numchips = 0; flash_base = 0; for (i = 0; i < MAX_CHIPS; i++) { chip = &mtd.chips[i]; if (probe_chip(&mtd, flash_base, chip) == 0) { mtd.size += chip->size; mtd.numchips++; flash_base+= chip->size; } else break; } return 0;}int flash_erase(unsigned long addr, unsigned long size){ return flash_erase_internal(&mtd, addr, size);}int flash_read(unsigned long from, unsigned long len, unsigned long *retlen, unsigned char *buf){ return flash_read_internal(&mtd, from, len, retlen, buf);}int flash_write(unsigned long to, unsigned long len, unsigned long *retlen, const unsigned char *buf){ return flash_write_internal(&mtd, to, len, retlen, buf);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -