📄 amd_flash.c
字号:
{ 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_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_AMD,
dev_id: AM29BDS643D,
name: "AMD AM29BDS643D",
size: 0x00800000,
numeraseregions: 3,
regions: {
{ offset: 0x000000, erasesize: 0x10000, numblocks: 96 },
{ offset: 0x600000, erasesize: 0x10000, numblocks: 31 },
{ offset: 0x7f0000, 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 }
}
}, {
mfr_id: MANUFACTURER_HYNIX,
dev_id: HY29LV800B,
name: "Hynix HY29LV800B",
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_HYNIX,
dev_id: HY29LV800T,
name: "Hynix HY29LV800T",
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 }
}
}
};
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*)mmalloc(sizeof(*mtd));
if (!mtd) {
printk("%s: malloc 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("%s: Found no AMD compatible device at location zero\n",
map->name);
mfree(mtd);
return NULL;
}
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;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -