⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 amd_flash.c

📁 比较好的VIVI开发源码
💻 C
📖 第 1 页 / 共 3 页
字号:
			{ 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 + -