📄 amd_flash.c
字号:
.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_TOSHIBA, .dev_id = TC58FVB160, .name = "Toshiba TC58FVB160", .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_FUJITSU, .dev_id = MBM29LV160BE, .name = "Fujitsu MBM29LV160BE", .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_AMD, .dev_id = AM29LV800BB, .name = "AMD AM29LV800BB", .size = 0x00100000, .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 = 15 } } }, { .mfr_id = MANUFACTURER_AMD, .dev_id = AM29F800BB, .name = "AMD AM29F800BB", .size = 0x00100000, .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 = 15 } } }, { .mfr_id = MANUFACTURER_AMD, .dev_id = AM29LV800BT, .name = "AMD AM29LV800BT", .size = 0x00100000, .numeraseregions = 4, .regions = { { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 15 }, { .offset = 0x0F0000, .erasesize = 0x08000, .numblocks = 1 }, { .offset = 0x0F8000, .erasesize = 0x02000, .numblocks = 2 }, { .offset = 0x0FC000, .erasesize = 0x04000, .numblocks = 1 } } }, { .mfr_id = MANUFACTURER_AMD, .dev_id = AM29F800BT, .name = "AMD AM29F800BT", .size = 0x00100000, .numeraseregions = 4, .regions = { { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 15 }, { .offset = 0x0F0000, .erasesize = 0x08000, .numblocks = 1 }, { .offset = 0x0F8000, .erasesize = 0x02000, .numblocks = 2 }, { .offset = 0x0FC000, .erasesize = 0x04000, .numblocks = 1 } } }, { .mfr_id = MANUFACTURER_AMD, .dev_id = AM29LV800BB, .name = "AMD AM29LV800BB", .size = 0x00100000, .numeraseregions = 4, .regions = { { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 15 }, { .offset = 0x0F0000, .erasesize = 0x08000, .numblocks = 1 }, { .offset = 0x0F8000, .erasesize = 0x02000, .numblocks = 2 }, { .offset = 0x0FC000, .erasesize = 0x04000, .numblocks = 1 } } }, { .mfr_id = MANUFACTURER_FUJITSU, .dev_id = MBM29LV800BB, .name = "Fujitsu MBM29LV800BB", .size = 0x00100000, .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 = 15 } } }, { .mfr_id = MANUFACTURER_ST, .dev_id = M29W800T, .name = "ST M29W800T", .size = 0x00100000, .numeraseregions = 4, .regions = { { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 15 }, { .offset = 0x0F0000, .erasesize = 0x08000, .numblocks = 1 }, { .offset = 0x0F8000, .erasesize = 0x02000, .numblocks = 2 }, { .offset = 0x0FC000, .erasesize = 0x04000, .numblocks = 1 } } }, { .mfr_id = MANUFACTURER_ST, .dev_id = M29W160DT, .name = "ST M29W160DT", .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_ST, .dev_id = M29W160DB, .name = "ST M29W160DB", .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_AMD, .dev_id = AM29BDS323D, .name = "AMD AM29BDS323D", .size = 0x00400000, .numeraseregions = 3, .regions = { { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 48 }, { .offset = 0x300000, .erasesize = 0x10000, .numblocks = 15 }, { .offset = 0x3f0000, .erasesize = 0x02000, .numblocks = 8 }, } }, { .mfr_id = MANUFACTURER_ATMEL, .dev_id = AT49xV16x, .name = "Atmel AT49xV16x", .size = 0x00200000, .numeraseregions = 2, .regions = { { .offset = 0x000000, .erasesize = 0x02000, .numblocks = 8 }, { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 31 } } }, { .mfr_id = MANUFACTURER_ATMEL, .dev_id = AT49xV16xT, .name = "Atmel AT49xV16xT", .size = 0x00200000, .numeraseregions = 2, .regions = { { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 }, { .offset = 0x1F0000, .erasesize = 0x02000, .numblocks = 8 } } } }; struct mtd_info *mtd; struct flchip chips[MAX_AMD_CHIPS]; int table_pos[MAX_AMD_CHIPS]; struct amd_flash_private temp; struct amd_flash_private *private; u_long size; unsigned long base; int i; int reg_idx; int offset; mtd = (struct mtd_info*)kmalloc(sizeof(*mtd), GFP_KERNEL); if (!mtd) { printk(KERN_WARNING "%s: kmalloc failed for info structure\n", map->name); return NULL; } memset(mtd, 0, sizeof(*mtd)); mtd->priv = map; memset(&temp, 0, sizeof(temp)); printk("%s: Probing for AMD compatible flash...\n", map->name); if ((table_pos[0] = probe_new_chip(mtd, 0, NULL, &temp, table, sizeof(table)/sizeof(table[0]))) == -1) { printk(KERN_WARNING "%s: Found no AMD compatible device at location zero\n", map->name); kfree(mtd); return NULL; } chips[0].start = 0; chips[0].state = FL_READY; chips[0].mutex = &chips[0]._spinlock; 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 = kmalloc(sizeof(struct mtd_erase_region_info) * mtd->numeraseregions, GFP_KERNEL); if (!mtd->eraseregions) { printk(KERN_WARNING "%s: Failed to allocate " "memory for MTD erase region info\n", map->name); kfree(mtd); map->fldrv_priv = NULL; return NULL; } 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->read = amd_flash_read; mtd->write = amd_flash_write; mtd->sync = amd_flash_sync; mtd->suspend = amd_flash_suspend; mtd->resume = amd_flash_resume; mtd->lock = amd_flash_lock; mtd->unlock = amd_flash_unlock; private = kmalloc(sizeof(*private) + (sizeof(struct flchip) * temp.numchips), GFP_KERNEL); if (!private) { printk(KERN_WARNING "%s: kmalloc failed for private structure\n", map->name); kfree(mtd); map->fldrv_priv = NULL; return NULL; } memcpy(private, &temp, sizeof(temp)); memcpy(private->chips, chips, sizeof(struct flchip) * private->numchips); for (i = 0; i < private->numchips; i++) { init_waitqueue_head(&private->chips[i].wq); spin_lock_init(&private->chips[i]._spinlock); } map->fldrv_priv = private; map->fldrv = &amd_flash_chipdrv; __module_get(THIS_MODULE); return mtd;}static inline int read_one_chip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf){ DECLARE_WAITQUEUE(wait, current); unsigned long timeo = jiffies + HZ;retry: spin_lock_bh(chip->mutex); if (chip->state != FL_READY){ printk(KERN_INFO "%s: waiting for chip to read, state = %d\n", map->name, chip->state); set_current_state(TASK_UNINTERRUPTIBLE); add_wait_queue(&chip->wq, &wait); spin_unlock_bh(chip->mutex); schedule(); remove_wait_queue(&chip->wq, &wait); if(signal_pending(current)) { return -EINTR; } timeo = jiffies + HZ; goto retry; } adr += chip->start; chip->state = FL_READY; map_copy_from(map, buf, adr, len); wake_up(&chip->wq); spin_unlock_bh(chip->mutex); return 0;}static int amd_flash_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf){ struct map_info *map = mtd->priv; struct amd_flash_private *private = map->fldrv_priv; unsigned long ofs; int chipnum; int ret = 0; if ((from + len) > mtd->size) { printk(KERN_WARNING "%s: read request past end of device " "(0x%lx)\n", map->name, (unsigned long)from + len); return -EINVAL; } /* Offset within the first chip that the first read should start. */ chipnum = (from >> private->chipshift); ofs = from - (chipnum << private->chipshift); *retlen = 0; while (len) { unsigned long this_len; if (chipnum >= private->numchips) { break; } if ((len + ofs - 1) >> private->chipshift) { this_len = (1 << private->chipshift) - ofs; } else { this_len = len; } ret = read_one_chip(map, &private->chips[chipnum], ofs, this_len, buf); if (ret) { break; } *retlen += this_len; len -= this_len; buf += this_len; ofs = 0; chipnum++; } return ret;}static int write_one_word(struct map_info *map, struct flchip *chip, unsigned long adr, __u32 datum){ unsigned long timeo = jiffies + HZ; struct amd_flash_private *private = map->fldrv_priv; DECLARE_WAITQUEUE(wait, current); int ret = 0; int times_left;retry: spin_lock_bh(chip->mutex); if (chip->state != FL_READY){ printk("%s: waiting for chip to write, state = %d\n", map->name, chip->state); set_current_state(TASK_UNINTERRUPTIBLE); add_wait_queue(&chip->wq, &wait); spin_unlock_bh(chip->mutex); schedule(); remove_wait_queue(&chip->wq, &wait); printk(KERN_INFO "%s: woke up to write\n", map->name); if(signal_pending(current)) return -EINTR; timeo = jiffies + HZ; goto retry; } chip->state = FL_WRITING; 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 (need_resched()) { spin_unlock_bh(chip->mutex); schedule(); spin_lock_bh(chip->mutex); } } if (!times_left) { printk(KERN_WARNING "%s: write to 0x%lx timed out!\n", map->name, adr); ret = -EIO; } else { __u32 verify; if ((verify = wide_read(map, adr)) != datum) { printk(KERN_WARNING "%s: write to 0x%lx failed. " "datum = %x, verify = %x\n", map->name, adr, datum, verify); ret = -EIO; } } DISABLE_VPP(map);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -