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

📄 cfi_cmdset_0001.c

📁 vivi源代码专为三星公司arm处理器开发的启动代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
 * vivi/drivers/mtd/cfi-intelext.c: Intel Extended Vendor Command Set
 *
 * Based on linux/drivers/mtd/chips/cfi_cmdset_0001.c
 *
 * $Id: cfi_cmdset_0001.c,v 1.1.1.1 2004/02/04 06:22:25 laputa Exp $
 *
 * History
 *
 * 2002-01-16: Nandy Lyu <nandy@mizi.com>
 *    - Initial code
 *
 */

#include "config.h"
#include "mtd/mtd.h"
#include "mtd/cfi.h"
#include "heap.h"
#include "printk.h"
#ifdef CONFIG_MSG_PROGRESS
#include "vivi_lib.h"
#endif
#include <types.h>
#include <errno.h>

static int cfi_intelext_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
static int cfi_intelext_write_buffers(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
static int cfi_intelext_erase_varsize(struct mtd_info *, struct erase_info *);
static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len);
static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len);

struct mtd_info *cfi_cmdset_0001(struct map_info *, int);

static struct mtd_info *cfi_intelext_setup (struct map_info *);


#ifdef CONFIG_DEBUG_CFI
static void cfi_tell_features(struct cfi_pri_intelext *extp)
{
        int i;
        printk("  Feature/Command Support: %4.4X\n", extp->FeatureSupport);
        printk("     - Chip Erase:         %s\n", extp->FeatureSupport&1?"supported":"unsupported");
        printk("     - Suspend Erase:      %s\n", extp->FeatureSupport&2?"supported":"unsupported");
        printk("     - Suspend Program:    %s\n", extp->FeatureSupport&4?"supported":"unsupported");
        printk("     - Legacy Lock/Unlock: %s\n", extp->FeatureSupport&8?"supported":"unsupported");
        printk("     - Queued Erase:       %s\n", extp->FeatureSupport&16?"supported":"unsupported");
        printk("     - Instant block lock: %s\n", extp->FeatureSupport&32?"supported":"unsupported");
        printk("     - Protection Bits:    %s\n", extp->FeatureSupport&64?"supported":"unsupported");
        printk("     - Page-mode read:     %s\n", extp->FeatureSupport&128?"supported":"unsupported");
        printk("     - Synchronous read:   %s\n", extp->FeatureSupport&256?"supported":"unsupported");
        for (i=9; i<32; i++) {
                if (extp->FeatureSupport & (1<<i))
                        printk("     - Unknown Bit %X:      supported\n", i);
        }

        printk("  Supported functions after Suspend: %2.2X\n", extp->SuspendCmdSupport);
        printk("     - Program after Erase Suspend: %s\n", extp->SuspendCmdSupport&1?"supported":"unsupported");
        for (i=1; i<8; i++) {
                if (extp->SuspendCmdSupport & (1<<i))
                        printk("     - Unknown Bit %X:               supported\n", i);
        }

        printk("  Block Status Register Mask: %4.4X\n", extp->BlkStatusRegMask);
        printk("     - Lock Bit Active:      %s\n", extp->BlkStatusRegMask&1?"yes":"no");
        printk("     - Valid Bit Active:     %s\n", extp->BlkStatusRegMask&2?"yes":"no");
        for (i=2; i<16; i++) {
                if (extp->BlkStatusRegMask & (1<<i))
                        printk("     - Unknown Bit %X Active: yes\n",i);
        }

        printk("  Vcc Logic Supply Optimum Program/Erase Voltage: %d.%d V\n",
               extp->VccOptimal >> 8, extp->VccOptimal & 0xf);
        if (extp->VppOptimal)
                printk("  Vpp Programming Supply Optimum Program/Erase Voltage: %d.%d V\n",
                       extp->VppOptimal >> 8, extp->VppOptimal & 0xf);
}
#endif

/* This routine is made available to other mtd code via
 * inter_module_register.  It must only be accessed through
 * inter_module_get which will bump the use count of this module.  The
 * addresses passed back in cfi are valid as long as the use count of
 * this module is non-zero, i.e. between inter_module_get and
 * inter_module_put.  Keith Owens <kaos@ocs.com.au> 29 Oct 2000.
 */
struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary)
{
        struct cfi_private *cfi = map->fldrv_priv;
        int i;
        __u32 base = cfi->chips[0].start;

        if (cfi->cfi_mode == CFI_MODE_CFI) {
                /* 
                 * It's a real CFI chip, not one for which the probe
                 * routine faked a CFI structure. So we read the feature
                 * table from it.
                 */
                __u16 adr = primary?cfi->cfiq->P_ADR:cfi->cfiq->A_ADR;
                struct cfi_pri_intelext *extp;
                int ofs_factor = cfi->interleave * cfi->device_type;

                //printk(" Intel/Sharp Extended Query Table at 0x%4.4X\n", adr);
                if (!adr)
                        return NULL;

                /* Switch it into Query Mode */
                cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);

                extp = mmalloc(sizeof(*extp));
                if (!extp) {
                        printk("Failed to allocate memory\n");
                        return NULL;
                }
         
                /* Read in the Extended Query Table */
                for (i=0; i<sizeof(*extp); i++) {
                        ((unsigned char *)extp)[i] = 
                                cfi_read_query(map, (base+((adr+i)*ofs_factor)));
                }
         
                if (extp->MajorVersion != '1' ||  
                    (extp->MinorVersion < '0' || extp->MinorVersion > '2')) { 
                        printk("  Unknown IntelExt Extended Query "
                               "version %c.%c.\n",  extp->MajorVersion,
                               extp->MinorVersion);
                        mfree(extp);
                        return NULL;
                }
         
                /* Do some byteswapping if necessary */
                extp->FeatureSupport = extp->FeatureSupport;
                extp->BlkStatusRegMask = extp->BlkStatusRegMask;
                extp->ProtRegAddr = extp->ProtRegAddr;
         
#ifdef CONFIG_DEBUG_CFI
                /* Tell the user about it in lots of lovely detail */
                cfi_tell_features(extp);
#endif

                /* Install our own private info structure */
                cfi->cmdset_priv = extp;
        }

        for (i=0; i< cfi->numchips; i++) {
                cfi->chips[i].word_write_time = 128;
                cfi->chips[i].buffer_write_time = 128;
                cfi->chips[i].erase_time = 1024;
        }

        /* Make sure it's in read mode */
        cfi_send_gen_cmd(0xff, 0x55, base, map, cfi, cfi->device_type, NULL);
        return cfi_intelext_setup(map);
}

static struct mtd_info *cfi_intelext_setup(struct map_info *map)
{
	struct cfi_private *cfi = map->fldrv_priv;
	struct mtd_info *mtd;
	unsigned long offset = 0;
	int i, j;
	unsigned long devsize = (1 << cfi->cfiq->DevSize) * cfi->interleave;

	mtd = mmalloc(sizeof(*mtd));

	if (!mtd) {
		printk("Failed to allocate memory for MTD device\n");
		mfree(cfi->cmdset_priv);
		return NULL;
	}

	memset(mtd, 0, sizeof(*mtd));
	mtd->priv = map;
	mtd->type = MTD_NORFLASH;
	mtd->size = devsize * cfi->numchips;
	
	mtd->numeraseregions = cfi->cfiq->NumEraseRegions * cfi->numchips;
	mtd->eraseregions = mmalloc(sizeof(struct mtd_erase_region_info) 
				    * mtd->numeraseregions);
	if (!mtd->eraseregions) { 
		printk("Failed to allocate memory for MTD erase region info\n");
		mfree(cfi->cmdset_priv);
		return NULL;
	}

	for (i = 0; i < cfi->cfiq->NumEraseRegions; i++) {
		unsigned long ernum, ersize;
		ersize = ((cfi->cfiq->EraseRegionInfo[i] >> 8) & ~0xff) * cfi->interleave;
		ernum = (cfi->cfiq->EraseRegionInfo[i] & 0xffff) + 1;

		if (mtd->erasesize < ersize) {
			mtd->erasesize = ersize;
		}
		for (j = 0; j < cfi->numchips; j++) {
			mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].offset = (j*devsize)+offset;
			mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].erasesize = ersize;
			mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].numblocks = ernum;
		}
		offset += (ersize * ernum);
	}

	if (offset != devsize) {
		/* Argh */
		printk("Sum of region (%lx) != total size of set of interleave chips (%lx)\n", offset, devsize);
		mfree(mtd->eraseregions);
		mfree(cfi->cmdset_priv);
		return NULL;
	}

	for (i = 0; i < mtd->numeraseregions; i++) {
		printk("%d: offset = 0x%x, size = 0x%x, blocks = %d\n", 
			i, mtd->eraseregions[i].offset,
			mtd->eraseregions[i].erasesize,
			mtd->eraseregions[i].numblocks);
	}

	/* Also select the correct geometry setup too */
	mtd->erase = cfi_intelext_erase_varsize;
#ifndef FORCE_WORD_WRTE
	if (cfi->cfiq->BufWriteTimeoutTyp) {
		printk("Using buffer write method\n");
		mtd->write = cfi_intelext_write_buffers;
	} else {
#else
	}
#endif
		printk("Using word write method\n");
		mtd->write = cfi_intelext_write_words;
	}

	mtd->lock = cfi_intelext_lock;
	mtd->unlock = cfi_intelext_unlock;
	mtd->flags = MTD_CAP_NORFLASH;
	mtd->name = map->name;
	return mtd;
}

int do_write_oneword(struct map_info *map, struct flchip *chip, 
                     unsigned long adr, cfi_word datum)
{
	struct cfi_private *cfi = map->fldrv_priv;
	cfi_word status = 0, status_OK;
	unsigned long timeo;

	adr += chip->start;

	/* Let's determine this according to the interleave only once */
	status_OK = CMD(0x80);

	/* 弊成 荤侩 沁澜 - 2002-06-25 nandy */
	timeo = cfi->cfiq->WordWriteTimeoutMax * 1000;

	ENABLE_VPP(map);
	cfi_write(map, CMD(0x40), adr);
	cfi_write(map, datum, adr);

	/* wait for it to be programmed */
	while (timeo > 0) {
		status = cfi_read(map, adr);
		if ((status & status_OK) == status_OK)
			break;
		timeo--;
	}

	/* done */
	DISABLE_VPP(map);
	/* clear status */
	cfi_write(map, CMD(0x50), adr);

	/* report errors */
	if (timeo <= 0) {
		printk("\nFailed do_write_oneword() operation\n");
		printk("  Offset = 0x%08lx, datum = 0x%08lx, status = 0x%08lx\n",
			adr, datum, status);
		cfi_write(map, CMD(0xff), adr);
		return -EIO;
	}

	cfi_write(map, CMD(0xff), adr);
	return 0;
}

static int cfi_intelext_write_words(struct mtd_info *mtd,  loff_t to, size_t len, size_t *retlen, const u_char *buf)
{
	struct map_info *map = mtd->priv;
	struct cfi_private *cfi = map->fldrv_priv;
	int ret = 0;
	int chipnum;
	unsigned long ofs;
	
	*retlen = 0;

	if (!len)
		return 0;

	chipnum = to >> cfi->chipshift;
	ofs = to - (chipnum << cfi->chipshift);

	/* It it's not bus-aligned, do the first byte write */
	if (ofs & (CFIDEV_BUSWIDTH-1)) {
		unsigned long bus_ofs = ofs & ~(CFIDEV_BUSWIDTH-1);
		int gap = ofs - bus_ofs;
		int i = 0, n = 0;
		u_char tmp_buf[8];
		cfi_word datum;

		while (gap--)
			tmp_buf[i++] = 0xff;
		while (len && i < CFIDEV_BUSWIDTH)
			tmp_buf[i++] = buf[n++], len--;
		while (i < CFIDEV_BUSWIDTH)
			tmp_buf[i++] = 0xff;

		if (cfi_buswidth_is_2()) {
			datum = *(__u16*)tmp_buf;
		} else if (cfi_buswidth_is_4()) {
			datum = *(__u32*)tmp_buf;
		} else if (cfi_buswidth_is_8()) {
			datum = *(__u64*)tmp_buf;
		} else {
			return -EINVAL;	/* should never happen, but be safe */
		}

		ret = do_write_oneword(map, &cfi->chips[chipnum], bus_ofs, datum);
		if (ret) return ret;

		ofs += n;
		buf += n;
		(*retlen) += n;

		if (ofs >> cfi->chipshift) {
			chipnum++;
			ofs = 0;
			if (chipnum == cfi->numchips) 
				return 0;
		}
	}

	while (len >= CFIDEV_BUSWIDTH) {
		cfi_word datum;

		if (cfi_buswidth_is_1()) {
			datum = *(__u8*)buf;
		} else if (cfi_buswidth_is_2()) {
			datum = *(__u16*)buf;
		} else if (cfi_buswidth_is_4()) {
			datum = *(__u32*)buf;
		} else if (cfi_buswidth_is_8()) {
			datum = *(__u64*)buf;
		} else {
			return -EINVAL;
		}

		ret = do_write_oneword(map, &cfi->chips[chipnum], ofs, datum);

		if (ret) return ret;

		ofs += CFIDEV_BUSWIDTH;
		buf += CFIDEV_BUSWIDTH;
		(*retlen) += CFIDEV_BUSWIDTH;
		len -= CFIDEV_BUSWIDTH;

		if (ofs >> cfi->chipshift) {
			chipnum++;
			ofs = 0;
			if (chipnum == cfi->numchips)
				return 0;
		}
	}

	if (len & (CFIDEV_BUSWIDTH-1)) {
		int i = 0, n = 0;
		u_char tmp_buf[8];
		cfi_word datum;

		while (len--)
			tmp_buf[i++] = buf[n++];
		while (i < CFIDEV_BUSWIDTH)
			tmp_buf[i++] = 0xff;

		if (cfi_buswidth_is_2()) {
			datum = *(__u16*)tmp_buf;
		} else if (cfi_buswidth_is_4()) {
			datum = *(__u32*)tmp_buf;
		} else if (cfi_buswidth_is_8()) {
			datum = *(__u64*)tmp_buf;
		} else {
			return -EINVAL;	/* should never happen, but be safe */
		}

		ret = do_write_oneword(map, &cfi->chips[chipnum], ofs, datum);

		if (ret)
			return ret;

		(*retlen) += n;
	}

	return 0;
}

static int do_write_buffer(struct map_info *map, struct flchip *chip,
                           unsigned long adr, const u_char *buf, int len)
{
	struct cfi_private *cfi = map->fldrv_priv;
	cfi_word status, status_OK;
	unsigned long cmd_adr, timeo;
	int wbufsize, z;

	wbufsize = CFIDEV_INTERLEAVE << cfi->cfiq->MaxBufWriteSize;
	adr += chip->start;
	cmd_adr = adr & ~(wbufsize - 1);

	/* Let's determinc this according to the interleave only once */
	status_OK = CMD(0x80);

	timeo = cfi->cfiq->BufWriteTimeoutMax * 1000;

	ENABLE_VPP(map);
	cfi_write(map, CMD(0xe8), cmd_adr);

	for (;;) {
		status = cfi_read(map, cmd_adr);
		if ((status & status_OK) == status_OK)
			break;

		if (timeo < 0) {
			/* Argh. Not ready for write to buffer */
			cfi_write(map, CMD(0x70), cmd_adr);
			DISABLE_VPP(map);
			printk("Chip not ready for buffer write. Xstatus = 0x%llx, status = %llx\n", (__u64)status, (__u64)cfi_read(map, cmd_adr));
			/* Odd. Clear status bits */
			cfi_write(map, CMD(0x50), cmd_adr);
			cfi_write(map, CMD(0x70), cmd_adr);
			cfi_write(map, CMD(0xff), adr);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -