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

📄 nand_legacy.c

📁 嵌入式试验箱S3C2410的bootloader源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	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 */#ifdef NAND_DEBUG	printf("NanD_Command (ReadID) got %x %x\n", mfr, id);#endif	if (mfr == 0xff || mfr == 0) {		/* No response - return failure */		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;				nand->bus16	 = nand_flash_ids[i].bus16; 				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;	NanD_Command (nand, NAND_CMD_READ0);	if (nand->bus16) {		u16 val;		while (cntr >= 16) {			val = READ_NAND (nandptr);			*data_buf++ = val & 0xff;			*data_buf++ = val >> 8;			val = READ_NAND (nandptr);			*data_buf++ = val & 0xff;			*data_buf++ = val >> 8;			val = READ_NAND (nandptr);			*data_buf++ = val & 0xff;			*data_buf++ = val >> 8;			val = READ_NAND (nandptr);			*data_buf++ = val & 0xff;			*data_buf++ = val >> 8;			val = READ_NAND (nandptr);			*data_buf++ = val & 0xff;			*data_buf++ = val >> 8;			val = READ_NAND (nandptr);			*data_buf++ = val & 0xff;			*data_buf++ = val >> 8;			val = READ_NAND (nandptr);			*data_buf++ = val & 0xff;			*data_buf++ = val >> 8;			val = READ_NAND (nandptr);			*data_buf++ = val & 0xff;			*data_buf++ = val >> 8;			cntr -= 16;		}		while (cntr > 0) {			val = READ_NAND (nandptr);			*data_buf++ = val & 0xff;			*data_buf++ = val >> 8;			cntr -= 2;		}	} else {		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);		if (nand->bus16) { 			NanD_Address(nand, ADDR_COLUMN_PAGE,				     (page << nand->page_shift) + (col >> 1));		} else { 			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);		if (nand->bus16) {			NanD_Address(nand, ADDR_COLUMN_PAGE,				     (page << nand->page_shift) + (col >> 1));		} else {			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 ! *  Change By www.arm9.net, if ecc_code is null, write without ECC */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;    int writecnt;#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 */    if (ecc_code)   /* www.arm9.net */    	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);		if (nand->bus16) {			NanD_Address (nand, ADDR_COLUMN_PAGE,				      (page << nand->page_shift) + (col >> 1));

⌨️ 快捷键说明

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