?? amd_flash.c
字號:
} chips[0].start = 0; temp.numchips = 1; for (size = mtd->size; size > 1; size >>= 1) { temp.chipshift++; } switch (temp.interleave) { case 2: temp.chipshift += 1; break; case 4: temp.chipshift += 2; break; } /* Find out if there are any more chips in the map. */ for (base = (1 << temp.chipshift); base < map->size; base += (1 << temp.chipshift)) { int numchips = temp.numchips; table_pos[numchips] = probe_new_chip(mtd, base, chips, &temp, table, sizeof(table)/sizeof(table[0])); } mtd->eraseregions = mmalloc(sizeof(struct mtd_erase_region_info) * mtd->numeraseregions); if (!mtd->eraseregions) { printk("%s: Failed to allocate " "memory for MTD erase region info\n", map->name); mfree(mtd); map->fldrv_priv = NULL; return 0; } reg_idx = 0; offset = 0; for (i = 0; i < temp.numchips; i++) { int dev_size; int j; dev_size = 0; for (j = 0; j < table[table_pos[i]].numeraseregions; j++) { mtd->eraseregions[reg_idx].offset = offset + (table[table_pos[i]].regions[j].offset * temp.interleave); mtd->eraseregions[reg_idx].erasesize = table[table_pos[i]].regions[j].erasesize * temp.interleave; mtd->eraseregions[reg_idx].numblocks = table[table_pos[i]].regions[j].numblocks; if (mtd->erasesize < mtd->eraseregions[reg_idx].erasesize) { mtd->erasesize = mtd->eraseregions[reg_idx].erasesize; } dev_size += mtd->eraseregions[reg_idx].erasesize * mtd->eraseregions[reg_idx].numblocks; reg_idx++; } offset += dev_size; } mtd->type = MTD_NORFLASH; mtd->flags = MTD_CAP_NORFLASH; mtd->name = map->name; mtd->erase = amd_flash_erase; mtd->write = amd_flash_write; mtd->lock = amd_flash_lock; mtd->unlock = amd_flash_unlock; private = mmalloc(sizeof(*private) + (sizeof(struct flchip) * temp.numchips)); if (!private) { printk("%s: kmalloc failed for private structure\n", map->name); mfree(mtd); map->fldrv_priv = NULL; return NULL; } memcpy(private, &temp, sizeof(temp)); memcpy(private->chips, chips, sizeof(struct flchip) * private->numchips); map->fldrv_priv = private; /* map->fldrv = &amd_flash_chipdrv; */ return mtd;}static int write_one_word(struct map_info *map, struct flchip *chip, unsigned long adr, __u32 datum){ struct amd_flash_private *private = map->fldrv_priv; int ret = 0; int times_left; adr += chip->start; ENABLE_VPP(map); send_cmd(map, chip->start, CMD_PROGRAM_UNLOCK_DATA); wide_write(map, datum, adr); times_left = 500000; while (times_left-- && flash_is_busy(map, adr, private->interleave)) ; if (!times_left) { printk("%s: write to 0x%lx timed out!\n", map->name, adr); ret = -EIO; } else { __u32 verify; if ((verify = wide_read(map, adr)) != datum) { printk("%s: write to 0x%lx failed. " "datum = %x, verify = %x\n", map->name, adr, datum, verify); ret = -EIO; } } DISABLE_VPP(map); return ret;}static int amd_flash_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 amd_flash_private *private = map->fldrv_priv; int ret = 0; int chipnum; unsigned long ofs; unsigned long chipstart; *retlen = 0; if (!len) { return 0; } chipnum = to >> private->chipshift; ofs = to - (chipnum << private->chipshift); chipstart = private->chips[chipnum].start; /* If it's not bus-aligned, do the first byte write. */ if (ofs & (map->buswidth - 1)) { unsigned long bus_ofs = ofs & ~(map->buswidth - 1); int i = ofs - bus_ofs; int n = 0; u_char tmp_buf[4]; __u32 datum;#if 0 /* comment out by nandy */ map->copy_from(map, tmp_buf, bus_ofs + private->chips[chipnum].start, map->buswidth);#endif while (len && i < map->buswidth) tmp_buf[i++] = buf[n++], len--; if (map->buswidth == 2) { datum = *(__u16*)tmp_buf; } else if (map->buswidth == 4) { datum = *(__u32*)tmp_buf; } else { return -EINVAL; /* should never happen, but be safe */ } ret = write_one_word(map, &private->chips[chipnum], bus_ofs, datum); if (ret) { return ret; } ofs += n; buf += n; (*retlen) += n; if (ofs >> private->chipshift) { chipnum++; ofs = 0; if (chipnum == private->numchips) { return 0; } } } /* We are now aligned, write as much as possible. */ while(len >= map->buswidth) { __u32 datum; if (map->buswidth == 1) { datum = *(__u8*)buf; } else if (map->buswidth == 2) { datum = *(__u16*)buf; } else if (map->buswidth == 4) { datum = *(__u32*)buf; } else { return -EINVAL; } ret = write_one_word(map, &private->chips[chipnum], ofs, datum); if (ret) { return ret; } ofs += map->buswidth; buf += map->buswidth; (*retlen) += map->buswidth; len -= map->buswidth; if (ofs >> private->chipshift) { chipnum++; ofs = 0; if (chipnum == private->numchips) { return 0; } chipstart = private->chips[chipnum].start; } } if (len & (map->buswidth - 1)) { int i = 0, n = 0; u_char tmp_buf[2]; __u32 datum;#if 0 /* comment out by nandy */ map->copy_from(map, tmp_buf, ofs + private->chips[chipnum].start, map->buswidth);#endif while (len--) { tmp_buf[i++] = buf[n++]; } if (map->buswidth == 2) { datum = *(__u16*)tmp_buf; } else if (map->buswidth == 4) { datum = *(__u32*)tmp_buf; } else { return -EINVAL; /* should never happen, but be safe */ } ret = write_one_word(map, &private->chips[chipnum], ofs, datum); if (ret) { return ret; } (*retlen) += n; } return 0;}static inline int erase_one_block(struct map_info *map, struct flchip *chip, unsigned long adr, u_long size){ unsigned long timeo = TIMEO; struct amd_flash_private *private = map->fldrv_priv; adr += chip->start; ENABLE_VPP(map); send_cmd(map, chip->start, CMD_SECTOR_ERASE_UNLOCK_DATA); send_cmd_to_addr(map, chip->start, CMD_SECTOR_ERASE_UNLOCK_DATA_2, adr); while (flash_is_busy(map, adr, private->interleave)) { /* OK Still waiting */ if (timeo < 0) { printk("%s: waiting for erase to complete " "timed out.\n", map->name); DISABLE_VPP(map); return -EIO; } udelay(1); } /* Verify every single word */ { int address; int error = 0; __u8 verify; for (address = adr; address < (adr + size); address++) { if ((verify = map->read8(map, address)) != 0xFF) { error = 1; break; } } if (error) { printk("%s: verify error at 0x%x, size %ld.\n", map->name, address, size); DISABLE_VPP(map); return -EIO; } } DISABLE_VPP(map); return 0;}static int amd_flash_erase(struct mtd_info *mtd, struct erase_info *instr){ struct map_info *map = mtd->priv; struct amd_flash_private *private = map->fldrv_priv; unsigned long adr, len; int chipnum; int ret = 0; int i; int first; struct mtd_erase_region_info *regions = mtd->eraseregions; if (instr->addr > mtd->size) { return -EINVAL; } if ((instr->len + instr->addr) > mtd->size) { return -EINVAL; } /* Check that both start and end of the requested erase are * aligned with the erasesize at the appropriate addresses. */ i = 0; /* Skip all erase regions which are ended before the start of the requested erase. Actually, to save on the calculations, we skip to the first erase region which starts after the start of the requested erase, and then go back one. */ while ((i < mtd->numeraseregions) && (instr->addr >= regions[i].offset)) { i++; } i--; /* OK, now i is pointing at the erase region in which this * erase request starts. Check the start of the requested * erase range is aligned with the erase size which is in * effect here. */ if (instr->addr & (regions[i].erasesize-1)) { return -EINVAL; } /* Remember the erase region we start on. */ first = i; /* Next, check that the end of the requested erase is aligned * with the erase region at that address. */ while ((i < mtd->numeraseregions) && ((instr->addr + instr->len) >= regions[i].offset)) { i++; } /* As before, drop back one to point at the region in which * the address actually falls. */ i--; if ((instr->addr + instr->len) & (regions[i].erasesize-1)) { return -EINVAL; } chipnum = instr->addr >> private->chipshift; adr = instr->addr - (chipnum << private->chipshift); len = instr->len; i = first; DPRINTK("Start erase\n"); while (len) { DPRINTK("remain length = 0x%lx\n", len); ret = erase_one_block(map, &private->chips[chipnum], adr, regions[i].erasesize); if (ret) { return ret; } adr += regions[i].erasesize; len -= regions[i].erasesize; if ((adr % (1 << private->chipshift)) == ((regions[i].offset + (regions[i].erasesize * regions[i].numblocks)) % (1 << private->chipshift))) { i++; } if (adr >> private->chipshift) { adr = 0; chipnum++; if (chipnum >= private->numchips) { break; } } } return 0;}#ifdef CONFIG_CMD_AMD_FLASHstruct mtd_info *amdstd_mtd;#define AMDFLASH_SIZE SZ_1M#define AMDFLASH_BUSWIDTH DEVICE_TYPE_X16#define AMDFLASH_BASE 0x08000000static voidamdstd_set_vpp(struct map_info *map, int vpp){ /* nothing */}static __u8 amdstd_read8(struct map_info *map, unsigned long ofs){ return readb(map->map_priv_1 + ofs); }static __u16 amdstd_read16(struct map_info *map, unsigned long ofs){ return readw(map->map_priv_1 + ofs); }static __u32 amdstd_read32(struct map_info *map, unsigned long ofs){ return readl(map->map_priv_1 + ofs); }static void amdstd_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len){ memcpy(to, (void *)(map->map_priv_1 + from), len);}static void amdstd_write8(struct map_info *map, __u8 d, unsigned long adr){ writeb(d, map->map_priv_1 + adr); }static void amdstd_write16(struct map_info *map, __u16 d, unsigned long adr){ writew(d, map->map_priv_1 + adr); }static void amdstd_write32(struct map_info *map, __u32 d, unsigned long adr){ writel(d, map->map_priv_1 + adr); }static void amdstd_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len){ memcpy((void *)(map->map_priv_1 + to), from, len);}static struct map_info amdstd_map = { name: "S3C2410 amd flash", read8: amdstd_read8, read16: amdstd_read16, read32: amdstd_read32, copy_from: amdstd_copy_from, write8: amdstd_write8, write16: amdstd_write16, write32: amdstd_write32, copy_to: amdstd_copy_to, map_priv_1: AMDFLASH_BASE, map_priv_2: -1,};static voidfill_map(struct map_info *map){ map->size = AMDFLASH_SIZE; map->buswidth = AMDFLASH_BUSWIDTH; /* DEVICE_TYPE_X16 */ map->set_vpp = amdstd_set_vpp;}static voidcommand_erase(int argc, const char **argv){ struct mtd_info *mtd = amdstd_mtd; struct erase_info instr; int ret; if (argc != 3) { printk("invalid 'amd erase' command: too few(many) arguments\n"); return; } instr.addr = strtoul(argv[1], NULL, 0, NULL); instr.len = strtoul(argv[2], NULL, 0, NULL); printk("Erase from 0x%08lx-0x%08lx... ", instr.addr, instr.addr + instr.len); ret = amd_flash_erase(mtd, &instr); if (ret) printk("failed.\n"); else printk("done.\n");}static voidcommand_write(int argc, const char **argv){ struct mtd_info *mtd = amdstd_mtd; loff_t ofs; size_t size; u_char *from; size_t retlen; if (argc != 4) { printk("invalid 'amd write' command: too few(many) arguments\n"); return; } ofs = (loff_t)strtoul(argv[1], NULL, 0, NULL); size = (size_t)strtoul(argv[2], NULL, 0, NULL); from = (u_char *)strtoul(argv[3], NULL, 0, NULL); amd_flash_write(mtd, ofs, size, &retlen, from); printk("retlen = 0x%x, %d-byte\n", retlen, retlen);}static voidcommand_probe(int arg, const char **argv){ fill_map(&amdstd_map); amdstd_mtd = amd_flash_probe(&amdstd_map);}static user_subcommand_t amd_cmds[] = { { "erase", command_erase, "amd erase <ofs> <size>\t\t-- erase a region" }, { "probe", command_probe, "amd probe\t\t\t-- probing AMD flash" }, { "write", command_write, "amd write <ofs> <size> <buf_addr>\t-- write images" }, { NULL, NULL, NULL }};voidcommand_amd(int argc, const char **argv){ switch (argc) { case 1: invalid_cmd("amd", amd_cmds); break; case 2: if (strncmp("help", argv[1], 4) == 0) { print_usage("", amd_cmds); break; } default: execsubcmd(amd_cmds, argc-1, argv+1); }}user_command_t amd_cmd = { "amd", command_amd, NULL, "amd [{cmds}]\t\t\t-- Manage AMD flash memory"};#endif /* CONFIG_CMD_AMD_FLASH */
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -