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

📄 cmd_nand.c.svn-base

📁 u-boot loader common files, like cpu, clock, environment...etc...
💻 SVN-BASE
📖 第 1 页 / 共 3 页
字号:
	return NanD_WaitReady(nand, 0);}/* NanD_Address: Set the current address for the flash chip */static int NanD_Address(struct nand_chip *nand, int numbytes, unsigned long ofs){	unsigned long nandptr;	int i;	nandptr = nand->IO_ADDR;	/* Assert the ALE (Address Latch Enable) line to the flash chip */	NAND_CTL_SETALE(nandptr);	/* Send the address */	/* Devices with 256-byte page are addressed as:	 * Column (bits 0-7), Page (bits 8-15, 16-23, 24-31)	 * there is no device on the market with page256	 * and more than 24 bits.	 * Devices with 512-byte page are addressed as:	 * Column (bits 0-7), Page (bits 9-16, 17-24, 25-31)	 * 25-31 is sent only if the chip support it.	 * bit 8 changes the read command to be sent	 * (NAND_CMD_READ0 or NAND_CMD_READ1).	 */	if (numbytes == ADDR_COLUMN || numbytes == ADDR_COLUMN_PAGE)		WRITE_NAND_ADDRESS(ofs, nandptr);	ofs = ofs >> nand->page_shift;	if (numbytes == ADDR_PAGE || numbytes == ADDR_COLUMN_PAGE)		for (i = 0; i < nand->pageadrlen; i++, ofs = ofs >> 8)			WRITE_NAND_ADDRESS(ofs, nandptr);	/* Lower the ALE line */	NAND_CTL_CLRALE(nandptr);	/* Wait for the chip to respond */	return NanD_WaitReady(nand, 1);}/* NanD_SelectChip: Select a given flash chip within the current floor */static inline int NanD_SelectChip(struct nand_chip *nand, int chip){	/* Wait for it to be ready */	return NanD_WaitReady(nand, 0);}/* NanD_IdentChip: Identify a given NAND chip given {floor,chip} */static int NanD_IdentChip(struct nand_chip *nand, int floor, int chip){	int mfr, id, i;	NAND_ENABLE_CE(nand);  /* set pin low */	/* Reset the chip */	if (NanD_Command(nand, NAND_CMD_RESET)) {#ifdef NAND_DEBUG		printf("NanD_Command (reset) for %d,%d returned true\n",		       floor, chip);#endif		NAND_DISABLE_CE(nand);  /* set pin high */		return 0;	}	/* Read the NAND chip ID: 1. Send ReadID command */	if (NanD_Command(nand, NAND_CMD_READID)) {#ifdef NAND_DEBUG		printf("NanD_Command (ReadID) for %d,%d returned true\n",		       floor, chip);#endif		NAND_DISABLE_CE(nand);  /* set pin high */		return 0;	}	/* Read the NAND chip ID: 2. Send address byte zero */	NanD_Address(nand, ADDR_COLUMN, 0);	/* Read the manufacturer and device id codes from the device */	mfr = READ_NAND(nand->IO_ADDR);	id = READ_NAND(nand->IO_ADDR);	NAND_DISABLE_CE(nand);  /* set pin high */	/* No response - return failure */	if (mfr == 0xff || mfr == 0) {#ifdef NAND_DEBUG		printf("NanD_Command (ReadID) got %d %d\n", mfr, id);#endif		return 0;	}	/* Check it's the same as the first chip we identified.	 * M-Systems say that any given nand_chip device should only	 * contain _one_ type of flash part, although that's not a	 * hardware restriction. */	if (nand->mfr) {		if (nand->mfr == mfr && nand->id == id)			return 1;	/* This is another the same the first */		else			printf("Flash chip at floor %d, chip %d is different:\n",			       floor, chip);	}	/* Print and store the manufacturer and ID codes. */	for (i = 0; nand_flash_ids[i].name != NULL; i++) {		if (mfr == nand_flash_ids[i].manufacture_id &&		    id == nand_flash_ids[i].model_id) {#ifdef NAND_DEBUG			printf("Flash chip found:\n\t Manufacturer ID: 0x%2.2X, "			       "Chip ID: 0x%2.2X (%s)\n", mfr, id,			       nand_flash_ids[i].name);#endif			if (!nand->mfr) {				nand->mfr = mfr;				nand->id = id;				nand->chipshift =				    nand_flash_ids[i].chipshift;				nand->page256 = nand_flash_ids[i].page256;				nand->eccsize = 256;				if (nand->page256) {					nand->oobblock = 256;					nand->oobsize = 8;					nand->page_shift = 8;				} else {					nand->oobblock = 512;					nand->oobsize = 16;					nand->page_shift = 9;				}				nand->pageadrlen =				    nand_flash_ids[i].pageadrlen;				nand->erasesize =				    nand_flash_ids[i].erasesize;				nand->chips_name =				    nand_flash_ids[i].name;				return 1;			}			return 0;		}	}#ifdef NAND_DEBUG	/* We haven't fully identified the chip. Print as much as we know. */	printf("Unknown flash chip found: %2.2X %2.2X\n",	       id, mfr);#endif	return 0;}/* NanD_ScanChips: Find all NAND chips present in a nand_chip, and identify them */static void NanD_ScanChips(struct nand_chip *nand){	int floor, chip;	int numchips[NAND_MAX_FLOORS];	int maxchips = NAND_MAX_CHIPS;	int ret = 1;	nand->numchips = 0;	nand->mfr = 0;	nand->id = 0;	/* For each floor, find the number of valid chips it contains */	for (floor = 0; floor < NAND_MAX_FLOORS; floor++) {		ret = 1;		numchips[floor] = 0;		for (chip = 0; chip < maxchips && ret != 0; chip++) {			ret = NanD_IdentChip(nand, floor, chip);			if (ret) {				numchips[floor]++;				nand->numchips++;			}		}	}	/* If there are none at all that we recognise, bail */	if (!nand->numchips) {#ifdef NAND_DEBUG		puts ("No NAND flash chips recognised.\n");#endif		return;	}	/* Allocate an array to hold the information for each chip */	nand->chips = malloc(sizeof(struct Nand) * nand->numchips);	if (!nand->chips) {		puts ("No memory for allocating chip info structures\n");		return;	}	ret = 0;	/* Fill out the chip array with {floor, chipno} for each	 * detected chip in the device. */	for (floor = 0; floor < NAND_MAX_FLOORS; floor++) {		for (chip = 0; chip < numchips[floor]; chip++) {			nand->chips[ret].floor = floor;			nand->chips[ret].chip = chip;			nand->chips[ret].curadr = 0;			nand->chips[ret].curmode = 0x50;			ret++;		}	}	/* Calculate and print the total size of the device */	nand->totlen = nand->numchips * (1 << nand->chipshift);#ifdef NAND_DEBUG	printf("%d flash chips found. Total nand_chip size: %ld MB\n",	       nand->numchips, nand->totlen >> 20);#endif}/* we need to be fast here, 1 us per read translates to 1 second per meg */static void NanD_ReadBuf(struct nand_chip *nand, u_char *data_buf, int cntr){	unsigned long nandptr = nand->IO_ADDR;	while (cntr >= 16) {		*data_buf++ = READ_NAND(nandptr);		*data_buf++ = READ_NAND(nandptr);		*data_buf++ = READ_NAND(nandptr);		*data_buf++ = READ_NAND(nandptr);		*data_buf++ = READ_NAND(nandptr);		*data_buf++ = READ_NAND(nandptr);		*data_buf++ = READ_NAND(nandptr);		*data_buf++ = READ_NAND(nandptr);		*data_buf++ = READ_NAND(nandptr);		*data_buf++ = READ_NAND(nandptr);		*data_buf++ = READ_NAND(nandptr);		*data_buf++ = READ_NAND(nandptr);		*data_buf++ = READ_NAND(nandptr);		*data_buf++ = READ_NAND(nandptr);		*data_buf++ = READ_NAND(nandptr);		*data_buf++ = READ_NAND(nandptr);		cntr -= 16;	}	while (cntr > 0) {		*data_buf++ = READ_NAND(nandptr);		cntr--;	}}/* * NAND read with ECC */static int nand_read_ecc(struct nand_chip *nand, size_t start, size_t len,		 size_t * retlen, u_char *buf, u_char *ecc_code){	int col, page;	int ecc_status = 0;#ifdef CONFIG_MTD_NAND_ECC	int j;	int ecc_failed = 0;	u_char *data_poi;	u_char ecc_calc[6];#endif	/* Do not allow reads past end of device */	if ((start + len) > nand->totlen) {		printf ("%s: Attempt read beyond end of device %x %x %x\n", __FUNCTION__, (uint) start, (uint) len, (uint) nand->totlen);		*retlen = 0;		return -1;	}	/* First we calculate the starting page */	/*page = shr(start, nand->page_shift);*/	page = start >> nand->page_shift;	/* Get raw starting column */	col = start & (nand->oobblock - 1);	/* Initialize return value */	*retlen = 0;	/* Select the NAND device */	NAND_ENABLE_CE(nand);  /* set pin low */	/* Loop until all data read */	while (*retlen < len) {#ifdef CONFIG_MTD_NAND_ECC		/* Do we have this page in cache ? */		if (nand->cache_page == page)			goto readdata;		/* Send the read command */		NanD_Command(nand, NAND_CMD_READ0);		NanD_Address(nand, ADDR_COLUMN_PAGE, (page << nand->page_shift) + col);		/* Read in a page + oob data */		NanD_ReadBuf(nand, nand->data_buf, nand->oobblock + nand->oobsize);		/* copy data into cache, for read out of cache and if ecc fails */		if (nand->data_cache)			memcpy (nand->data_cache, nand->data_buf, nand->oobblock + nand->oobsize);		/* Pick the ECC bytes out of the oob data */		for (j = 0; j < 6; j++)			ecc_code[j] = nand->data_buf[(nand->oobblock + oob_config.ecc_pos[j])];		/* Calculate the ECC and verify it */		/* If block was not written with ECC, skip ECC */		if (oob_config.eccvalid_pos != -1 &&		    (nand->data_buf[nand->oobblock + oob_config.eccvalid_pos] & 0x0f) != 0x0f) {			nand_calculate_ecc (&nand->data_buf[0], &ecc_calc[0]);			switch (nand_correct_data (&nand->data_buf[0], &ecc_code[0], &ecc_calc[0])) {			case -1:				printf ("%s: Failed ECC read, page 0x%08x\n", __FUNCTION__, page);				ecc_failed++;				break;			case 1:			case 2:	/* transfer ECC corrected data to cache */				if (nand->data_cache)					memcpy (nand->data_cache, nand->data_buf, 256);				break;			}		}		if (oob_config.eccvalid_pos != -1 &&		    nand->oobblock == 512 && (nand->data_buf[nand->oobblock + oob_config.eccvalid_pos] & 0xf0) != 0xf0) {			nand_calculate_ecc (&nand->data_buf[256], &ecc_calc[3]);			switch (nand_correct_data (&nand->data_buf[256], &ecc_code[3], &ecc_calc[3])) {			case -1:				printf ("%s: Failed ECC read, page 0x%08x\n", __FUNCTION__, page);				ecc_failed++;				break;			case 1:			case 2:	/* transfer ECC corrected data to cache */				if (nand->data_cache)					memcpy (&nand->data_cache[256], &nand->data_buf[256], 256);				break;			}		}readdata:		/* Read the data from ECC data buffer into return buffer */		data_poi = (nand->data_cache) ? nand->data_cache : nand->data_buf;		data_poi += col;		if ((*retlen + (nand->oobblock - col)) >= len) {			memcpy (buf + *retlen, data_poi, len - *retlen);			*retlen = len;		} else {			memcpy (buf + *retlen, data_poi,  nand->oobblock - col);			*retlen += nand->oobblock - col;		}		/* Set cache page address, invalidate, if ecc_failed */		nand->cache_page = (nand->data_cache && !ecc_failed) ? page : -1;		ecc_status += ecc_failed;		ecc_failed = 0;#else		/* Send the read command */		NanD_Command(nand, NAND_CMD_READ0);		NanD_Address(nand, ADDR_COLUMN_PAGE, (page << nand->page_shift) + col);		/* Read the data directly into the return buffer */		if ((*retlen + (nand->oobblock - col)) >= len) {			NanD_ReadBuf(nand, buf + *retlen, len - *retlen);			*retlen = len;			/* We're done */			continue;		} else {			NanD_ReadBuf(nand, buf + *retlen, nand->oobblock - col);			*retlen += nand->oobblock - col;			}#endif		/* For subsequent reads align to page boundary. */		col = 0;		/* Increment page address */		page++;	}	/* De-select the NAND device */	NAND_DISABLE_CE(nand);  /* set pin high */	/*	 * Return success, if no ECC failures, else -EIO	 * fs driver will take care of that, because	 * retlen == desired len and result == -EIO	 */	return ecc_status ? -1 : 0;}/* *	Nand_page_program function is used for write and writev ! */static int nand_write_page (struct nand_chip *nand,			    int page, int col, int last, u_char * ecc_code){	int i;	unsigned long nandptr = nand->IO_ADDR;#ifdef CONFIG_MTD_NAND_ECC#ifdef CONFIG_MTD_NAND_VERIFY_WRITE	int ecc_bytes = (nand->oobblock == 512) ? 6 : 3;#endif#endif	/* pad oob area */	for (i = nand->oobblock; i < nand->oobblock + nand->oobsize; i++)		nand->data_buf[i] = 0xff;#ifdef CONFIG_MTD_NAND_ECC	/* Zero out the ECC array */	for (i = 0; i < 6; i++)		ecc_code[i] = 0x00;	/* Read back previous written data, if col > 0 */	if (col) {		NanD_Command(nand, NAND_CMD_READ0);		NanD_Address(nand, ADDR_COLUMN_PAGE, (page << nand->page_shift) + col);		for (i = 0; i < col; i++)			nand->data_buf[i] = READ_NAND (nandptr);	}	/* Calculate and write the ECC if we have enough data */	if ((col < nand->eccsize) && (last >= nand->eccsize)) {		nand_calculate_ecc (&nand->data_buf[0], &(ecc_code[0]));		for (i = 0; i < 3; i++)			nand->data_buf[(nand->oobblock + oob_config.ecc_pos[i])] = ecc_code[i];		if (oob_config.eccvalid_pos != -1)			nand->data_buf[nand->oobblock + oob_config.eccvalid_pos] = 0xf0;	}	/* Calculate and write the second ECC if we have enough data */	if ((nand->oobblock == 512) && (last == nand->oobblock)) {		nand_calculate_ecc (&nand->data_buf[256], &(ecc_code[3]));		for (i = 3; i < 6; i++)			nand->data_buf[(nand->oobblock + oob_config.ecc_pos[i])] = ecc_code[i];		if (oob_config.eccvalid_pos != -1)			nand->data_buf[nand->oobblock + oob_config.eccvalid_pos] &= 0x0f;	}#endif	/* Prepad for partial page programming !!! */	for (i = 0; i < col; i++)		nand->data_buf[i] = 0xff;	/* Postpad for partial page programming !!! oob is already padded */	for (i = last; i < nand->oobblock; i++)		nand->data_buf[i] = 0xff;	/* Send command to begin auto page programming */	NanD_Command(nand, NAND_CMD_READ0);	NanD_Command(nand, NAND_CMD_SEQIN);	NanD_Address(nand, ADDR_COLUMN_PAGE, (page << nand->page_shift) + col);	/* Write out complete page of data */	for (i = 0; i < (nand->oobblock + nand->oobsize); i++)		WRITE_NAND(nand->data_buf[i], nand->IO_ADDR);	/* Send command to actually program the data */	NanD_Command(nand, NAND_CMD_PAGEPROG);	NanD_Command(nand, NAND_CMD_STATUS);#ifdef NAND_NO_RB	{ u_char ret_val;	  do{		ret_val = READ_NAND(nandptr);	/* wait till ready */	  } while((ret_val & 0x40) != 0x40);	}#endif	/* See if device thinks it succeeded */	if (READ_NAND(nand->IO_ADDR) & 0x01) {		printf ("%s: Failed write, page 0x%08x, ", __FUNCTION__, page);		return -1;	}#ifdef CONFIG_MTD_NAND_VERIFY_WRITE	/*	 * The NAND device assumes that it is always writing to	 * a cleanly erased page. Hence, it performs its internal	 * write verification only on bits that transitioned from	 * 1 to 0. The device does NOT verify the whole page on a	 * byte by byte basis. It is possible that the page was	 * not completely erased or the page is becoming unusable	 * due to wear. The read with ECC would catch the error	 * later when the ECC page check fails, but we would rather	 * catch it early in the page write stage. Better to write	 * no data than invalid data.	 */	/* Send command to read back the page */	if (col < nand->eccsize)		NanD_Command(nand, NAND_CMD_READ0);	else		NanD_Command(nand, NAND_CMD_READ1);	NanD_Address(nand, ADDR_COLUMN_PAGE, (page << nand->page_shift) + col);	/* Loop through and verify the data */	for (i = col; i < last; i++) {		if (nand->data_buf[i] != readb (nand->IO_ADDR)) {			printf ("%s: Failed write verify, page 0x%08x ", __FUNCTION__, page);			return -1;		}	}#ifdef CONFIG_MTD_NAND_ECC	/*	 * We also want to check that the ECC bytes wrote	 * correctly for the same reasons stated above.	 */	NanD_Command(nand, NAND_CMD_READOOB);	NanD_Address(nand, ADDR_COLUMN_PAGE, (page << nand->page_shift) + col);	for (i = 0; i < nand->oobsize; i++)		nand->data_buf[i] = readb (nand->IO_ADDR);	for (i = 0; i < ecc_bytes; i++) {		if ((nand->data_buf[(oob_config.ecc_pos[i])] != ecc_code[i]) && ecc_code[i]) {			printf ("%s: Failed ECC write "			       "verify, page 0x%08x, " "%6i bytes were succesful\n", __FUNCTION__, page, i);			return -1;		}	}#endif#endif	return 0;}static int nand_write_ecc (struct nand_chip* nand, size_t to, size_t len,			   size_t * retlen, const u_char * buf, u_char * ecc_code){	int i, page, col, cnt, ret = 0;	/* Do not allow write past end of device */	if ((to + len) > nand->totlen) {		printf ("%s: Attempt to write past end of page\n", __FUNCTION__);		return -1;	}	/* Shift to get page */	page = ((int) to) >> nand->page_shift;	/* Get the starting column */	col = to & (nand->oobblock - 1);	/* Initialize return length value */	*retlen = 0;	/* Select the NAND device */#ifdef CONFIG_OMAP1510	archflashwp(0,0);#endif    	NAND_ENABLE_CE(nand);  /* set pin low */	/* Check the WP bit */	NanD_Command(nand, NAND_CMD_STATUS);	if (!(READ_NAND(nand->IO_ADDR) & 0x80)) {		printf ("%s: Device is write protected!!!\n", __FUNCTION__);		ret = -1;		goto out;	}	/* Loop until all data is written */

⌨️ 快捷键说明

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