Merge branch 'master' of git://git.denx.de/u-boot-nand-flash
This commit is contained in:
		
						commit
						c413a004ea
					
				|  | @ -231,12 +231,18 @@ print: | |||
| #ifdef CONFIG_CMD_NAND_LOCK_UNLOCK | ||||
| static void print_status(ulong start, ulong end, ulong erasesize, int status) | ||||
| { | ||||
| 	/*
 | ||||
| 	 * Micron NAND flash (e.g. MT29F4G08ABADAH4) BLOCK LOCK READ STATUS is | ||||
| 	 * not the same as others.  Instead of bit 1 being lock, it is | ||||
| 	 * #lock_tight. To make the driver support either format, ignore bit 1 | ||||
| 	 * and use only bit 0 and bit 2. | ||||
| 	 */ | ||||
| 	printf("%08lx - %08lx: %08lx blocks %s%s%s\n", | ||||
| 		start, | ||||
| 		end - 1, | ||||
| 		(end - start) / erasesize, | ||||
| 		((status & NAND_LOCK_STATUS_TIGHT) ?  "TIGHT " : ""), | ||||
| 		((status & NAND_LOCK_STATUS_LOCK) ?  "LOCK " : ""), | ||||
| 		(!(status & NAND_LOCK_STATUS_UNLOCK) ?  "LOCK " : ""), | ||||
| 		((status & NAND_LOCK_STATUS_UNLOCK) ?  "UNLOCK " : "")); | ||||
| } | ||||
| 
 | ||||
|  | @ -749,11 +755,18 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) | |||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
| 	if (strcmp(cmd, "unlock") == 0) { | ||||
| 	if (strncmp(cmd, "unlock", 5) == 0) { | ||||
| 		int allexcept = 0; | ||||
| 
 | ||||
| 		s = strchr(cmd, '.'); | ||||
| 
 | ||||
| 		if (s && !strcmp(s, ".allexcept")) | ||||
| 			allexcept = 1; | ||||
| 
 | ||||
| 		if (arg_off_size(argc - 2, argv + 2, &dev, &off, &size) < 0) | ||||
| 			return 1; | ||||
| 
 | ||||
| 		if (!nand_unlock(&nand_info[dev], off, size)) { | ||||
| 		if (!nand_unlock(&nand_info[dev], off, size, allexcept)) { | ||||
| 			puts("NAND flash successfully unlocked\n"); | ||||
| 		} else { | ||||
| 			puts("Error unlocking NAND flash, " | ||||
|  | @ -807,7 +820,7 @@ U_BOOT_CMD( | |||
| 	"\n" | ||||
| 	"nand lock [tight] [status]\n" | ||||
| 	"    bring nand to lock state or display locked pages\n" | ||||
| 	"nand unlock [offset] [size] - unlock section" | ||||
| 	"nand unlock[.allexcept] [offset] [size] - unlock section" | ||||
| #endif | ||||
| #ifdef CONFIG_ENV_OFFSET_OOB | ||||
| 	"\n" | ||||
|  |  | |||
|  | @ -228,6 +228,8 @@ NAND locking command (for chips with active LOCKPRE pin) | |||
|   "nand unlock [offset] [size]" | ||||
|   unlock consecutive area (can be called multiple times for different areas) | ||||
| 
 | ||||
|   "nand unlock.allexcept [offset] [size]" | ||||
|   unlock all except specified consecutive area | ||||
| 
 | ||||
| I have tested the code with board containing 128MiB NAND large page chips | ||||
| and 32MiB small page chips. | ||||
|  |  | |||
|  | @ -25,168 +25,23 @@ | |||
| #if defined(CONFIG_MX25) || defined(CONFIG_MX27) || defined(CONFIG_MX35) | ||||
| #include <asm/arch/imx-regs.h> | ||||
| #endif | ||||
| #include <fsl_nfc.h> | ||||
| 
 | ||||
| #define DRIVER_NAME "mxc_nand" | ||||
| 
 | ||||
| /*
 | ||||
|  * TODO: Use same register defs here as nand_spl mxc nand driver. | ||||
|  */ | ||||
| /*
 | ||||
|  * Register map and bit definitions for the Freescale NAND Flash Controller | ||||
|  * present in various i.MX devices. | ||||
|  * | ||||
|  * MX31 and MX27 have version 1 which has | ||||
|  * 	4 512 byte main buffers and | ||||
|  * 	4 16 byte spare buffers | ||||
|  * 	to support up to 2K byte pagesize nand. | ||||
|  * 	Reading or writing a 2K page requires 4 FDI/FDO cycles. | ||||
|  * | ||||
|  * MX25 has version 1.1 which has | ||||
|  * 	8 512 byte main buffers and | ||||
|  * 	8 64 byte spare buffers | ||||
|  * 	to support up to 4K byte pagesize nand. | ||||
|  * 	Reading or writing a 2K or 4K page requires only 1 FDI/FDO cycle. | ||||
|  *      Also some of registers are moved and/or changed meaning as seen below. | ||||
|  */ | ||||
| #if defined(CONFIG_MX31) || defined(CONFIG_MX27) | ||||
| #define MXC_NFC_V1 | ||||
| #elif defined(CONFIG_MX25) || defined(CONFIG_MX35) | ||||
| #define MXC_NFC_V1_1 | ||||
| #else | ||||
| #warning "MXC NFC version not defined" | ||||
| #endif | ||||
| 
 | ||||
| #if defined(MXC_NFC_V1) | ||||
| #define NAND_MXC_NR_BUFS		4 | ||||
| #define NAND_MXC_SPARE_BUF_SIZE		16 | ||||
| #define NAND_MXC_REG_OFFSET		0xe00 | ||||
| #define is_mxc_nfc_11() 		0 | ||||
| #elif defined(MXC_NFC_V1_1) | ||||
| #define NAND_MXC_NR_BUFS		8 | ||||
| #define NAND_MXC_SPARE_BUF_SIZE		64 | ||||
| #define NAND_MXC_REG_OFFSET		0x1e00 | ||||
| #define is_mxc_nfc_11() 		1 | ||||
| #else | ||||
| #error "define CONFIG_NAND_MXC_VXXX to use mtd mxc nand driver" | ||||
| #endif | ||||
| struct nfc_regs { | ||||
| 	uint8_t main_area[NAND_MXC_NR_BUFS][0x200]; | ||||
| 	uint8_t spare_area[NAND_MXC_NR_BUFS][NAND_MXC_SPARE_BUF_SIZE]; | ||||
| 	/*
 | ||||
| 	 * reserved size is offset of nfc registers | ||||
| 	 * minus total main and spare sizes | ||||
| 	 */ | ||||
| 	uint8_t reserved1[NAND_MXC_REG_OFFSET | ||||
| 		- NAND_MXC_NR_BUFS * (512 + NAND_MXC_SPARE_BUF_SIZE)]; | ||||
| #if defined(MXC_NFC_V1) | ||||
| 	uint16_t nfc_buf_size; | ||||
| 	uint16_t reserved2; | ||||
| 	uint16_t nfc_buf_addr; | ||||
| 	uint16_t nfc_flash_addr; | ||||
| 	uint16_t nfc_flash_cmd; | ||||
| 	uint16_t nfc_config; | ||||
| 	uint16_t nfc_ecc_status_result; | ||||
| 	uint16_t nfc_rsltmain_area; | ||||
| 	uint16_t nfc_rsltspare_area; | ||||
| 	uint16_t nfc_wrprot; | ||||
| 	uint16_t nfc_unlockstart_blkaddr; | ||||
| 	uint16_t nfc_unlockend_blkaddr; | ||||
| 	uint16_t nfc_nf_wrprst; | ||||
| 	uint16_t nfc_config1; | ||||
| 	uint16_t nfc_config2; | ||||
| #elif defined(MXC_NFC_V1_1) | ||||
| 	uint16_t reserved2[2]; | ||||
| 	uint16_t nfc_buf_addr; | ||||
| 	uint16_t nfc_flash_addr; | ||||
| 	uint16_t nfc_flash_cmd; | ||||
| 	uint16_t nfc_config; | ||||
| 	uint16_t nfc_ecc_status_result; | ||||
| 	uint16_t nfc_ecc_status_result2; | ||||
| 	uint16_t nfc_spare_area_size; | ||||
| 	uint16_t nfc_wrprot; | ||||
| 	uint16_t reserved3[2]; | ||||
| 	uint16_t nfc_nf_wrprst; | ||||
| 	uint16_t nfc_config1; | ||||
| 	uint16_t nfc_config2; | ||||
| 	uint16_t reserved4; | ||||
| 	uint16_t nfc_unlockstart_blkaddr; | ||||
| 	uint16_t nfc_unlockend_blkaddr; | ||||
| 	uint16_t nfc_unlockstart_blkaddr1; | ||||
| 	uint16_t nfc_unlockend_blkaddr1; | ||||
| 	uint16_t nfc_unlockstart_blkaddr2; | ||||
| 	uint16_t nfc_unlockend_blkaddr2; | ||||
| 	uint16_t nfc_unlockstart_blkaddr3; | ||||
| 	uint16_t nfc_unlockend_blkaddr3; | ||||
| #endif | ||||
| }; | ||||
| 
 | ||||
| /*
 | ||||
|  * Set INT to 0, FCMD to 1, rest to 0 in NFC_CONFIG2 Register | ||||
|  * for Command operation | ||||
|  */ | ||||
| #define NFC_CMD            0x1 | ||||
| 
 | ||||
| /*
 | ||||
|  * Set INT to 0, FADD to 1, rest to 0 in NFC_CONFIG2 Register | ||||
|  * for Address operation | ||||
|  */ | ||||
| #define NFC_ADDR           0x2 | ||||
| 
 | ||||
| /*
 | ||||
|  * Set INT to 0, FDI to 1, rest to 0 in NFC_CONFIG2 Register | ||||
|  * for Input operation | ||||
|  */ | ||||
| #define NFC_INPUT          0x4 | ||||
| 
 | ||||
| /*
 | ||||
|  * Set INT to 0, FDO to 001, rest to 0 in NFC_CONFIG2 Register | ||||
|  * for Data Output operation | ||||
|  */ | ||||
| #define NFC_OUTPUT         0x8 | ||||
| 
 | ||||
| /*
 | ||||
|  * Set INT to 0, FD0 to 010, rest to 0 in NFC_CONFIG2 Register | ||||
|  * for Read ID operation | ||||
|  */ | ||||
| #define NFC_ID             0x10 | ||||
| 
 | ||||
| /*
 | ||||
|  * Set INT to 0, FDO to 100, rest to 0 in NFC_CONFIG2 Register | ||||
|  * for Read Status operation | ||||
|  */ | ||||
| #define NFC_STATUS         0x20 | ||||
| 
 | ||||
| /*
 | ||||
|  * Set INT to 1, rest to 0 in NFC_CONFIG2 Register for Read | ||||
|  * Status operation | ||||
|  */ | ||||
| #define NFC_INT            0x8000 | ||||
| 
 | ||||
| #ifdef MXC_NFC_V1_1 | ||||
| #define NFC_4_8N_ECC	(1 << 0) | ||||
| #else | ||||
| #define NFC_4_8N_ECC	0 | ||||
| #endif | ||||
| #define NFC_SP_EN           (1 << 2) | ||||
| #define NFC_ECC_EN          (1 << 3) | ||||
| #define NFC_BIG             (1 << 5) | ||||
| #define NFC_RST             (1 << 6) | ||||
| #define NFC_CE              (1 << 7) | ||||
| #define NFC_ONE_CYCLE       (1 << 8) | ||||
| 
 | ||||
| typedef enum {false, true} bool; | ||||
| 
 | ||||
| struct mxc_nand_host { | ||||
| 	struct mtd_info		mtd; | ||||
| 	struct nand_chip	*nand; | ||||
| 	struct mtd_info			mtd; | ||||
| 	struct nand_chip		*nand; | ||||
| 
 | ||||
| 	struct nfc_regs __iomem	*regs; | ||||
| 	int			spare_only; | ||||
| 	int			status_request; | ||||
| 	int			pagesize_2k; | ||||
| 	int			clk_act; | ||||
| 	uint16_t		col_addr; | ||||
| 	unsigned int		page_addr; | ||||
| 	struct fsl_nfc_regs __iomem	*regs; | ||||
| 	int				spare_only; | ||||
| 	int				status_request; | ||||
| 	int				pagesize_2k; | ||||
| 	int				clk_act; | ||||
| 	uint16_t			col_addr; | ||||
| 	unsigned int			page_addr; | ||||
| }; | ||||
| 
 | ||||
| static struct mxc_nand_host mxc_host; | ||||
|  | @ -222,7 +77,7 @@ static struct nand_ecclayout nand_hw_eccoob2k = { | |||
| 	.oobfree = { {2, 4}, {11, 11}, {27, 11}, {43, 11}, {59, 5} }, | ||||
| }; | ||||
| #endif | ||||
| #elif defined(MXC_NFC_V1_1) | ||||
| #elif defined(MXC_NFC_V2_1) | ||||
| #ifndef CONFIG_SYS_NAND_LARGEPAGE | ||||
| static struct nand_ecclayout nand_hw_eccoob = { | ||||
| 	.eccbytes = 9, | ||||
|  | @ -268,8 +123,7 @@ static int is_16bit_nand(void) | |||
| #elif defined(CONFIG_MX25) || defined(CONFIG_MX35) | ||||
| static int is_16bit_nand(void) | ||||
| { | ||||
| 	struct ccm_regs *ccm = | ||||
| 		(struct ccm_regs *)IMX_CCM_BASE; | ||||
| 	struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE; | ||||
| 
 | ||||
| 	if (readl(&ccm->rcsr) & CCM_RCSR_NF_16BIT_SEL) | ||||
| 		return 1; | ||||
|  | @ -304,10 +158,10 @@ static void wait_op_done(struct mxc_nand_host *host, int max_retries, | |||
| 	uint32_t tmp; | ||||
| 
 | ||||
| 	while (max_retries-- > 0) { | ||||
| 		if (readw(&host->regs->nfc_config2) & NFC_INT) { | ||||
| 			tmp = readw(&host->regs->nfc_config2); | ||||
| 		if (readw(&host->regs->config2) & NFC_INT) { | ||||
| 			tmp = readw(&host->regs->config2); | ||||
| 			tmp  &= ~NFC_INT; | ||||
| 			writew(tmp, &host->regs->nfc_config2); | ||||
| 			writew(tmp, &host->regs->config2); | ||||
| 			break; | ||||
| 		} | ||||
| 		udelay(1); | ||||
|  | @ -326,8 +180,8 @@ static void send_cmd(struct mxc_nand_host *host, uint16_t cmd) | |||
| { | ||||
| 	MTDDEBUG(MTD_DEBUG_LEVEL3, "send_cmd(host, 0x%x)\n", cmd); | ||||
| 
 | ||||
| 	writew(cmd, &host->regs->nfc_flash_cmd); | ||||
| 	writew(NFC_CMD, &host->regs->nfc_config2); | ||||
| 	writew(cmd, &host->regs->flash_cmd); | ||||
| 	writew(NFC_CMD, &host->regs->config2); | ||||
| 
 | ||||
| 	/* Wait for operation to complete */ | ||||
| 	wait_op_done(host, TROP_US_DELAY, cmd); | ||||
|  | @ -342,8 +196,8 @@ static void send_addr(struct mxc_nand_host *host, uint16_t addr) | |||
| { | ||||
| 	MTDDEBUG(MTD_DEBUG_LEVEL3, "send_addr(host, 0x%x)\n", addr); | ||||
| 
 | ||||
| 	writew(addr, &host->regs->nfc_flash_addr); | ||||
| 	writew(NFC_ADDR, &host->regs->nfc_config2); | ||||
| 	writew(addr, &host->regs->flash_addr); | ||||
| 	writew(NFC_ADDR, &host->regs->config2); | ||||
| 
 | ||||
| 	/* Wait for operation to complete */ | ||||
| 	wait_op_done(host, TROP_US_DELAY, addr); | ||||
|  | @ -359,7 +213,7 @@ static void send_prog_page(struct mxc_nand_host *host, uint8_t buf_id, | |||
| 	if (spare_only) | ||||
| 		MTDDEBUG(MTD_DEBUG_LEVEL1, "send_prog_page (%d)\n", spare_only); | ||||
| 
 | ||||
| 	if (is_mxc_nfc_11()) { | ||||
| 	if (is_mxc_nfc_21()) { | ||||
| 		int i; | ||||
| 		/*
 | ||||
| 		 *  The controller copies the 64 bytes of spare data from | ||||
|  | @ -375,19 +229,19 @@ static void send_prog_page(struct mxc_nand_host *host, uint8_t buf_id, | |||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	writew(buf_id, &host->regs->nfc_buf_addr); | ||||
| 	writew(buf_id, &host->regs->buf_addr); | ||||
| 
 | ||||
| 	/* Configure spare or page+spare access */ | ||||
| 	if (!host->pagesize_2k) { | ||||
| 		uint16_t config1 = readw(&host->regs->nfc_config1); | ||||
| 		uint16_t config1 = readw(&host->regs->config1); | ||||
| 		if (spare_only) | ||||
| 			config1 |= NFC_SP_EN; | ||||
| 		else | ||||
| 			config1 &= ~(NFC_SP_EN); | ||||
| 		writew(config1, &host->regs->nfc_config1); | ||||
| 			config1 &= ~NFC_SP_EN; | ||||
| 		writew(config1, &host->regs->config1); | ||||
| 	} | ||||
| 
 | ||||
| 	writew(NFC_INPUT, &host->regs->nfc_config2); | ||||
| 	writew(NFC_INPUT, &host->regs->config2); | ||||
| 
 | ||||
| 	/* Wait for operation to complete */ | ||||
| 	wait_op_done(host, TROP_US_DELAY, spare_only); | ||||
|  | @ -402,24 +256,24 @@ static void send_read_page(struct mxc_nand_host *host, uint8_t buf_id, | |||
| { | ||||
| 	MTDDEBUG(MTD_DEBUG_LEVEL3, "send_read_page (%d)\n", spare_only); | ||||
| 
 | ||||
| 	writew(buf_id, &host->regs->nfc_buf_addr); | ||||
| 	writew(buf_id, &host->regs->buf_addr); | ||||
| 
 | ||||
| 	/* Configure spare or page+spare access */ | ||||
| 	if (!host->pagesize_2k) { | ||||
| 		uint32_t config1 = readw(&host->regs->nfc_config1); | ||||
| 		uint32_t config1 = readw(&host->regs->config1); | ||||
| 		if (spare_only) | ||||
| 			config1 |= NFC_SP_EN; | ||||
| 		else | ||||
| 			config1 &= ~NFC_SP_EN; | ||||
| 		writew(config1, &host->regs->nfc_config1); | ||||
| 		writew(config1, &host->regs->config1); | ||||
| 	} | ||||
| 
 | ||||
| 	writew(NFC_OUTPUT, &host->regs->nfc_config2); | ||||
| 	writew(NFC_OUTPUT, &host->regs->config2); | ||||
| 
 | ||||
| 	/* Wait for operation to complete */ | ||||
| 	wait_op_done(host, TROP_US_DELAY, spare_only); | ||||
| 
 | ||||
| 	if (is_mxc_nfc_11()) { | ||||
| 	if (is_mxc_nfc_21()) { | ||||
| 		int i; | ||||
| 
 | ||||
| 		/*
 | ||||
|  | @ -442,14 +296,14 @@ static void send_read_id(struct mxc_nand_host *host) | |||
| 	uint16_t tmp; | ||||
| 
 | ||||
| 	/* NANDFC buffer 0 is used for device ID output */ | ||||
| 	writew(0x0, &host->regs->nfc_buf_addr); | ||||
| 	writew(0x0, &host->regs->buf_addr); | ||||
| 
 | ||||
| 	/* Read ID into main buffer */ | ||||
| 	tmp = readw(&host->regs->nfc_config1); | ||||
| 	tmp = readw(&host->regs->config1); | ||||
| 	tmp &= ~NFC_SP_EN; | ||||
| 	writew(tmp, &host->regs->nfc_config1); | ||||
| 	writew(tmp, &host->regs->config1); | ||||
| 
 | ||||
| 	writew(NFC_ID, &host->regs->nfc_config2); | ||||
| 	writew(NFC_ID, &host->regs->config2); | ||||
| 
 | ||||
| 	/* Wait for operation to complete */ | ||||
| 	wait_op_done(host, TROP_US_DELAY, 0); | ||||
|  | @ -469,14 +323,14 @@ static uint16_t get_dev_status(struct mxc_nand_host *host) | |||
| 	/* store the main area1 first word, later do recovery */ | ||||
| 	store = readl(main_buf); | ||||
| 	/* NANDFC buffer 1 is used for device status */ | ||||
| 	writew(1, &host->regs->nfc_buf_addr); | ||||
| 	writew(1, &host->regs->buf_addr); | ||||
| 
 | ||||
| 	/* Read status into main buffer */ | ||||
| 	tmp = readw(&host->regs->nfc_config1); | ||||
| 	tmp = readw(&host->regs->config1); | ||||
| 	tmp &= ~NFC_SP_EN; | ||||
| 	writew(tmp, &host->regs->nfc_config1); | ||||
| 	writew(tmp, &host->regs->config1); | ||||
| 
 | ||||
| 	writew(NFC_STATUS, &host->regs->nfc_config2); | ||||
| 	writew(NFC_STATUS, &host->regs->config2); | ||||
| 
 | ||||
| 	/* Wait for operation to complete */ | ||||
| 	wait_op_done(host, TROP_US_DELAY, 0); | ||||
|  | @ -501,6 +355,19 @@ static int mxc_nand_dev_ready(struct mtd_info *mtd) | |||
| 	return 1; | ||||
| } | ||||
| 
 | ||||
| static void _mxc_nand_enable_hwecc(struct mtd_info *mtd, int on) | ||||
| { | ||||
| 	struct nand_chip *nand_chip = mtd->priv; | ||||
| 	struct mxc_nand_host *host = nand_chip->priv; | ||||
| 	uint16_t tmp = readw(&host->regs->config1); | ||||
| 
 | ||||
| 	if (on) | ||||
| 		tmp |= NFC_ECC_EN; | ||||
| 	else | ||||
| 		tmp &= ~NFC_ECC_EN; | ||||
| 	writew(tmp, &host->regs->config1); | ||||
| } | ||||
| 
 | ||||
| #ifdef CONFIG_MXC_NAND_HWECC | ||||
| static void mxc_nand_enable_hwecc(struct mtd_info *mtd, int mode) | ||||
| { | ||||
|  | @ -510,20 +377,7 @@ static void mxc_nand_enable_hwecc(struct mtd_info *mtd, int mode) | |||
| 	 */ | ||||
| } | ||||
| 
 | ||||
| #ifdef MXC_NFC_V1_1 | ||||
| static void _mxc_nand_enable_hwecc(struct mtd_info *mtd, int on) | ||||
| { | ||||
| 	struct nand_chip *nand_chip = mtd->priv; | ||||
| 	struct mxc_nand_host *host = nand_chip->priv; | ||||
| 	uint16_t tmp = readw(&host->regs->nfc_config1); | ||||
| 
 | ||||
| 	if (on) | ||||
| 		tmp |= NFC_ECC_EN; | ||||
| 	else | ||||
| 		tmp &= ~NFC_ECC_EN; | ||||
| 	writew(tmp, &host->regs->nfc_config1); | ||||
| } | ||||
| 
 | ||||
| #ifdef MXC_NFC_V2_1 | ||||
| static int mxc_nand_read_oob_syndrome(struct mtd_info *mtd, | ||||
| 				      struct nand_chip *chip, | ||||
| 				      int page, int sndcmd) | ||||
|  | @ -616,7 +470,7 @@ static int mxc_nand_read_page_raw_syndrome(struct mtd_info *mtd, | |||
| 	size = mtd->oobsize - (oob - chip->oob_poi); | ||||
| 	if (size) | ||||
| 		chip->read_buf(mtd, oob, size); | ||||
| 	_mxc_nand_enable_hwecc(mtd, 0); | ||||
| 	_mxc_nand_enable_hwecc(mtd, 1); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
|  | @ -799,7 +653,7 @@ static int mxc_nand_correct_data(struct mtd_info *mtd, u_char *dat, | |||
| { | ||||
| 	struct nand_chip *nand_chip = mtd->priv; | ||||
| 	struct mxc_nand_host *host = nand_chip->priv; | ||||
| 	uint16_t ecc_status = readw(&host->regs->nfc_ecc_status_result); | ||||
| 	uint32_t ecc_status = readl(&host->regs->ecc_status_result); | ||||
| 	int subpages = mtd->writesize / nand_chip->subpagesize; | ||||
| 	int pg2blk_shift = nand_chip->phys_erase_shift - | ||||
| 			   nand_chip->page_shift; | ||||
|  | @ -832,7 +686,6 @@ static int mxc_nand_correct_data(struct mtd_info *mtd, u_char *dat, | |||
| #define mxc_nand_write_page_syndrome NULL | ||||
| #define mxc_nand_write_page_raw_syndrome NULL | ||||
| #define mxc_nand_write_oob_syndrome NULL | ||||
| #define mxc_nfc_11_nand_correct_data NULL | ||||
| 
 | ||||
| static int mxc_nand_correct_data(struct mtd_info *mtd, u_char *dat, | ||||
| 				 u_char *read_ecc, u_char *calc_ecc) | ||||
|  | @ -845,7 +698,7 @@ static int mxc_nand_correct_data(struct mtd_info *mtd, u_char *dat, | |||
| 	 * additional correction.  2-Bit errors cannot be corrected by | ||||
| 	 * HW ECC, so we need to return failure | ||||
| 	 */ | ||||
| 	uint16_t ecc_status = readw(&host->regs->nfc_ecc_status_result); | ||||
| 	uint16_t ecc_status = readw(&host->regs->ecc_status_result); | ||||
| 
 | ||||
| 	if (((ecc_status & 0x3) == 2) || ((ecc_status >> 2) == 2)) { | ||||
| 		MTDDEBUG(MTD_DEBUG_LEVEL0, | ||||
|  | @ -1208,7 +1061,7 @@ void mxc_nand_command(struct mtd_info *mtd, unsigned command, | |||
| 	case NAND_CMD_PAGEPROG: | ||||
| 		send_prog_page(host, 0, host->spare_only); | ||||
| 
 | ||||
| 		if (host->pagesize_2k && !is_mxc_nfc_11()) { | ||||
| 		if (host->pagesize_2k && is_mxc_nfc_1()) { | ||||
| 			/* data in 4 areas */ | ||||
| 			send_prog_page(host, 1, host->spare_only); | ||||
| 			send_prog_page(host, 2, host->spare_only); | ||||
|  | @ -1258,7 +1111,7 @@ void mxc_nand_command(struct mtd_info *mtd, unsigned command, | |||
| 			send_cmd(host, NAND_CMD_READSTART); | ||||
| 			/* read for each AREA */ | ||||
| 			send_read_page(host, 0, host->spare_only); | ||||
| 			if (!is_mxc_nfc_11()) { | ||||
| 			if (is_mxc_nfc_1()) { | ||||
| 				send_read_page(host, 1, host->spare_only); | ||||
| 				send_read_page(host, 2, host->spare_only); | ||||
| 				send_read_page(host, 3, host->spare_only); | ||||
|  | @ -1284,24 +1137,6 @@ void mxc_nand_command(struct mtd_info *mtd, unsigned command, | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| #ifdef MXC_NFC_V1_1 | ||||
| static void mxc_setup_config1(void) | ||||
| { | ||||
| 	uint16_t tmp; | ||||
| 
 | ||||
| 	tmp = readw(&host->regs->nfc_config1); | ||||
| 	tmp |= NFC_ONE_CYCLE; | ||||
| 	tmp |= NFC_4_8N_ECC; | ||||
| 	writew(tmp, &host->regs->nfc_config1); | ||||
| 	if (host->pagesize_2k) | ||||
| 		writew(64/2, &host->regs->nfc_spare_area_size); | ||||
| 	else | ||||
| 		writew(16/2, &host->regs->nfc_spare_area_size); | ||||
| } | ||||
| #else | ||||
| #define mxc_setup_config1() | ||||
| #endif | ||||
| 
 | ||||
| #ifdef CONFIG_SYS_NAND_USE_FLASH_BBT | ||||
| 
 | ||||
| static u8 bbt_pattern[] = {'B', 'b', 't', '0' }; | ||||
|  | @ -1333,7 +1168,6 @@ int board_nand_init(struct nand_chip *this) | |||
| { | ||||
| 	struct mtd_info *mtd; | ||||
| 	uint16_t tmp; | ||||
| 	int err = 0; | ||||
| 
 | ||||
| #ifdef CONFIG_SYS_NAND_USE_FLASH_BBT | ||||
| 	this->options |= NAND_USE_FLASH_BBT; | ||||
|  | @ -1359,14 +1193,14 @@ int board_nand_init(struct nand_chip *this) | |||
| 	this->read_buf = mxc_nand_read_buf; | ||||
| 	this->verify_buf = mxc_nand_verify_buf; | ||||
| 
 | ||||
| 	host->regs = (struct nfc_regs __iomem *)CONFIG_MXC_NAND_REGS_BASE; | ||||
| 	host->regs = (struct fsl_nfc_regs __iomem *)CONFIG_MXC_NAND_REGS_BASE; | ||||
| 	host->clk_act = 1; | ||||
| 
 | ||||
| #ifdef CONFIG_MXC_NAND_HWECC | ||||
| 	this->ecc.calculate = mxc_nand_calculate_ecc; | ||||
| 	this->ecc.hwctl = mxc_nand_enable_hwecc; | ||||
| 	this->ecc.correct = mxc_nand_correct_data; | ||||
| 	if (is_mxc_nfc_11()) { | ||||
| 	if (is_mxc_nfc_21()) { | ||||
| 		this->ecc.mode = NAND_ECC_HW_SYNDROME; | ||||
| 		this->ecc.read_page = mxc_nand_read_page_syndrome; | ||||
| 		this->ecc.read_page_raw = mxc_nand_read_page_raw_syndrome; | ||||
|  | @ -1383,43 +1217,15 @@ int board_nand_init(struct nand_chip *this) | |||
| 	host->pagesize_2k = 0; | ||||
| 
 | ||||
| 	this->ecc.size = 512; | ||||
| 	tmp = readw(&host->regs->nfc_config1); | ||||
| 	tmp |= NFC_ECC_EN; | ||||
| 	writew(tmp, &host->regs->nfc_config1); | ||||
| 	_mxc_nand_enable_hwecc(mtd, 1); | ||||
| #else | ||||
| 	this->ecc.layout = &nand_soft_eccoob; | ||||
| 	this->ecc.mode = NAND_ECC_SOFT; | ||||
| 	tmp = readw(&host->regs->nfc_config1); | ||||
| 	tmp &= ~NFC_ECC_EN; | ||||
| 	writew(tmp, &host->regs->nfc_config1); | ||||
| 	_mxc_nand_enable_hwecc(mtd, 0); | ||||
| #endif | ||||
| 	/* Reset NAND */ | ||||
| 	this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * preset operation | ||||
| 	 * Unlock the internal RAM Buffer | ||||
| 	 */ | ||||
| 	writew(0x2, &host->regs->nfc_config); | ||||
| 
 | ||||
| 	/* Blocks to be unlocked */ | ||||
| 	writew(0x0, &host->regs->nfc_unlockstart_blkaddr); | ||||
| 	/* Originally (Freescale LTIB 2.6.21) 0x4000 was written to the
 | ||||
| 	 * unlockend_blkaddr, but the magic 0x4000 does not always work | ||||
| 	 * when writing more than some 32 megabytes (on 2k page nands) | ||||
| 	 * However 0xFFFF doesn't seem to have this kind | ||||
| 	 * of limitation (tried it back and forth several times). | ||||
| 	 * The linux kernel driver sets this to 0xFFFF for the v2 controller | ||||
| 	 * only, but probably this was not tested there for v1. | ||||
| 	 * The very same limitation seems to apply to this kernel driver. | ||||
| 	 * This might be NAND chip specific and the i.MX31 datasheet is | ||||
| 	 * extremely vague about the semantics of this register. | ||||
| 	 */ | ||||
| 	writew(0xFFFF, &host->regs->nfc_unlockend_blkaddr); | ||||
| 
 | ||||
| 	/* Unlock Block Command for given address range */ | ||||
| 	writew(0x4, &host->regs->nfc_wrprot); | ||||
| 
 | ||||
| 	/* NAND bus width determines access functions used by upper layer */ | ||||
| 	if (is_16bit_nand()) | ||||
| 		this->options |= NAND_BUSWIDTH_16; | ||||
|  | @ -1431,6 +1237,41 @@ int board_nand_init(struct nand_chip *this) | |||
| 	host->pagesize_2k = 0; | ||||
| 	this->ecc.layout = &nand_hw_eccoob; | ||||
| #endif | ||||
| 	mxc_setup_config1(); | ||||
| 	return err; | ||||
| 
 | ||||
| #ifdef MXC_NFC_V2_1 | ||||
| 	tmp = readw(&host->regs->config1); | ||||
| 	tmp |= NFC_ONE_CYCLE; | ||||
| 	tmp |= NFC_4_8N_ECC; | ||||
| 	writew(tmp, &host->regs->config1); | ||||
| 	if (host->pagesize_2k) | ||||
| 		writew(64/2, &host->regs->spare_area_size); | ||||
| 	else | ||||
| 		writew(16/2, &host->regs->spare_area_size); | ||||
| #endif | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * preset operation | ||||
| 	 * Unlock the internal RAM Buffer | ||||
| 	 */ | ||||
| 	writew(0x2, &host->regs->config); | ||||
| 
 | ||||
| 	/* Blocks to be unlocked */ | ||||
| 	writew(0x0, &host->regs->unlockstart_blkaddr); | ||||
| 	/* Originally (Freescale LTIB 2.6.21) 0x4000 was written to the
 | ||||
| 	 * unlockend_blkaddr, but the magic 0x4000 does not always work | ||||
| 	 * when writing more than some 32 megabytes (on 2k page nands) | ||||
| 	 * However 0xFFFF doesn't seem to have this kind | ||||
| 	 * of limitation (tried it back and forth several times). | ||||
| 	 * The linux kernel driver sets this to 0xFFFF for the v2 controller | ||||
| 	 * only, but probably this was not tested there for v1. | ||||
| 	 * The very same limitation seems to apply to this kernel driver. | ||||
| 	 * This might be NAND chip specific and the i.MX31 datasheet is | ||||
| 	 * extremely vague about the semantics of this register. | ||||
| 	 */ | ||||
| 	writew(0xFFFF, &host->regs->unlockend_blkaddr); | ||||
| 
 | ||||
| 	/* Unlock Block Command for given address range */ | ||||
| 	writew(0x4, &host->regs->wrprot); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
|  |  | |||
|  | @ -2573,14 +2573,13 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, | |||
| 	mtd->writesize = le32_to_cpu(p->byte_per_page); | ||||
| 	mtd->erasesize = le32_to_cpu(p->pages_per_block) * mtd->writesize; | ||||
| 	mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page); | ||||
| 	chip->chipsize = (uint64_t)le32_to_cpu(p->blocks_per_lun) * mtd->erasesize; | ||||
| 	chip->chipsize = le32_to_cpu(p->blocks_per_lun); | ||||
| 	chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count; | ||||
| 	*busw = 0; | ||||
| 	if (le16_to_cpu(p->features) & 1) | ||||
| 		*busw = NAND_BUSWIDTH_16; | ||||
| 
 | ||||
| 	chip->options &= ~NAND_CHIPOPTIONS_MSK; | ||||
| 	chip->options |= (NAND_NO_READRDY | | ||||
| 			NAND_NO_AUTOINCR) & NAND_CHIPOPTIONS_MSK; | ||||
| 	chip->options |= NAND_NO_READRDY | NAND_NO_AUTOINCR; | ||||
| 
 | ||||
| 	return 1; | ||||
| } | ||||
|  | @ -2752,8 +2751,7 @@ static const struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, | |||
| 		} | ||||
| 	} | ||||
| 	/* Get chip options, preserve non chip based options */ | ||||
| 	chip->options &= ~NAND_CHIPOPTIONS_MSK; | ||||
| 	chip->options |= type->options & NAND_CHIPOPTIONS_MSK; | ||||
| 	chip->options |= type->options; | ||||
| 
 | ||||
| 	/* Check if chip is a not a samsung device. Do not clear the
 | ||||
| 	 * options for chips which are not having an extended id. | ||||
|  |  | |||
|  | @ -207,12 +207,6 @@ int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts) | |||
|  * Support for locking / unlocking operations of some NAND devices | ||||
|  *****************************************************************************/ | ||||
| 
 | ||||
| #define NAND_CMD_LOCK		0x2a | ||||
| #define NAND_CMD_LOCK_TIGHT	0x2c | ||||
| #define NAND_CMD_UNLOCK1	0x23 | ||||
| #define NAND_CMD_UNLOCK2	0x24 | ||||
| #define NAND_CMD_LOCK_STATUS	0x7a | ||||
| 
 | ||||
| /**
 | ||||
|  * nand_lock: Set all pages of NAND flash chip to the LOCK or LOCK-TIGHT | ||||
|  *	      state | ||||
|  | @ -271,7 +265,6 @@ int nand_lock(struct mtd_info *mtd, int tight) | |||
|  *			>0 lock status: | ||||
|  *			  bitfield with the following combinations: | ||||
|  *			  NAND_LOCK_STATUS_TIGHT: page in tight state | ||||
|  *			  NAND_LOCK_STATUS_LOCK:  page locked | ||||
|  *			  NAND_LOCK_STATUS_UNLOCK: page unlocked | ||||
|  * | ||||
|  */ | ||||
|  | @ -300,7 +293,6 @@ int nand_get_lock_status(struct mtd_info *mtd, loff_t offset) | |||
| 	chip->cmdfunc(mtd, NAND_CMD_LOCK_STATUS, -1, page & chip->pagemask); | ||||
| 
 | ||||
| 	ret = chip->read_byte(mtd) & (NAND_LOCK_STATUS_TIGHT | ||||
| 					  | NAND_LOCK_STATUS_LOCK | ||||
| 					  | NAND_LOCK_STATUS_UNLOCK); | ||||
| 
 | ||||
|  out: | ||||
|  | @ -317,18 +309,21 @@ int nand_get_lock_status(struct mtd_info *mtd, loff_t offset) | |||
|  * @param start		start byte address | ||||
|  * @param length	number of bytes to unlock (must be a multiple of | ||||
|  *			page size nand->writesize) | ||||
|  * @param allexcept	if set, unlock everything not selected | ||||
|  * | ||||
|  * @return		0 on success, -1 in case of error | ||||
|  */ | ||||
| int nand_unlock(struct mtd_info *mtd, ulong start, ulong length) | ||||
| int nand_unlock(struct mtd_info *mtd, loff_t start, size_t length, | ||||
| 	int allexcept) | ||||
| { | ||||
| 	int ret = 0; | ||||
| 	int chipnr; | ||||
| 	int status; | ||||
| 	int page; | ||||
| 	struct nand_chip *chip = mtd->priv; | ||||
| 	printf ("nand_unlock: start: %08x, length: %d!\n", | ||||
| 		(int)start, (int)length); | ||||
| 
 | ||||
| 	debug("nand_unlock%s: start: %08llx, length: %d!\n", | ||||
| 		allexcept ? " (allexcept)" : "", start, length); | ||||
| 
 | ||||
| 	/* select the NAND device */ | ||||
| 	chipnr = (int)(start >> chip->chip_shift); | ||||
|  | @ -368,6 +363,15 @@ int nand_unlock(struct mtd_info *mtd, ulong start, ulong length) | |||
| 
 | ||||
| 	/* submit ADDRESS of LAST page to unlock */ | ||||
| 	page += (int)(length >> chip->page_shift); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Page addresses for unlocking are supposed to be block-aligned. | ||||
| 	 * At least some NAND chips use the low bit to indicate that the | ||||
| 	 * page range should be inverted. | ||||
| 	 */ | ||||
| 	if (allexcept) | ||||
| 		page |= 1; | ||||
| 
 | ||||
| 	chip->cmdfunc(mtd, NAND_CMD_UNLOCK2, -1, page & chip->pagemask); | ||||
| 
 | ||||
| 	/* call wait ready function */ | ||||
|  |  | |||
|  | @ -213,7 +213,6 @@ | |||
|  * NAND FLASH driver setup | ||||
|  */ | ||||
| #define CONFIG_NAND_MXC | ||||
| #define CONFIG_NAND_MXC_V1_1 | ||||
| #define CONFIG_MXC_NAND_REGS_BASE	(NFC_BASE_ADDR) | ||||
| #define CONFIG_SYS_MAX_NAND_DEVICE	1 | ||||
| #define CONFIG_SYS_NAND_BASE		(NFC_BASE_ADDR) | ||||
|  |  | |||
|  | @ -231,7 +231,6 @@ | |||
|  * NAND FLASH driver setup | ||||
|  */ | ||||
| #define CONFIG_NAND_MXC | ||||
| #define CONFIG_NAND_MXC_V1_1 | ||||
| #define CONFIG_MXC_NAND_REGS_BASE	(NFC_BASE_ADDR) | ||||
| #define CONFIG_SYS_MAX_NAND_DEVICE	1 | ||||
| #define CONFIG_SYS_NAND_BASE		(NFC_BASE_ADDR) | ||||
|  |  | |||
|  | @ -107,7 +107,6 @@ | |||
| 
 | ||||
| /* NAND */ | ||||
| #define CONFIG_NAND_MXC | ||||
| #define CONFIG_NAND_MXC_V1_1 | ||||
| #define CONFIG_MXC_NAND_REGS_BASE	(0xBB000000) | ||||
| #define CONFIG_SYS_MAX_NAND_DEVICE	1 | ||||
| #define CONFIG_SYS_NAND_BASE		(0xBB000000) | ||||
|  |  | |||
|  | @ -24,49 +24,48 @@ | |||
| #define __FSL_NFC_H | ||||
| 
 | ||||
| /*
 | ||||
|  * TODO: Use same register defs for nand_spl mxc nand driver | ||||
|  * and mtd mxc nand driver. | ||||
|  * Register map and bit definitions for the Freescale NAND Flash Controller | ||||
|  * present in various i.MX devices. | ||||
|  * | ||||
|  * Register map and bit definitions for the Freescale NAND Flash | ||||
|  * Controller present in various i.MX devices. | ||||
|  * MX31 and MX27 have version 1, which has: | ||||
|  *	4 512-byte main buffers and | ||||
|  *	4 16-byte spare buffers | ||||
|  *	to support up to 2K byte pagesize nand. | ||||
|  *	Reading or writing a 2K page requires 4 FDI/FDO cycles. | ||||
|  * | ||||
|  * MX31 and MX27 have version 1 which has | ||||
|  * 	4 512 byte main buffers and | ||||
|  * 	4 16 byte spare buffers | ||||
|  * 	to support up to 2K byte pagesize nand. | ||||
|  * 	Reading or writing a 2K page requires 4 FDI/FDO cycles. | ||||
|  * | ||||
|  * MX25 has version 1.1 which has | ||||
|  * 	8 512 byte main buffers and | ||||
|  * 	8 64 byte spare buffers | ||||
|  * 	to support up to 4K byte pagesize nand. | ||||
|  * 	Reading or writing a 2K or 4K page requires only 1 FDI/FDO cycle. | ||||
|  *      Also some of registers are moved and/or changed meaning as seen below. | ||||
|  * MX25 and MX35 have version 2.1, which has: | ||||
|  *	8 512-byte main buffers and | ||||
|  *	8 64-byte spare buffers | ||||
|  *	to support up to 4K byte pagesize nand. | ||||
|  *	Reading or writing a 2K or 4K page requires only 1 FDI/FDO cycle. | ||||
|  *	Also some of registers are moved and/or changed meaning as seen below. | ||||
|  */ | ||||
| #if defined(CONFIG_MX31) || defined(CONFIG_MX27) | ||||
| #if defined(CONFIG_MX27) || defined(CONFIG_MX31) | ||||
| #define MXC_NFC_V1 | ||||
| #elif defined(CONFIG_MX25) | ||||
| #define MXC_NFC_V1_1 | ||||
| #define is_mxc_nfc_1()		1 | ||||
| #define is_mxc_nfc_21()		0 | ||||
| #elif defined(CONFIG_MX25) || defined(CONFIG_MX35) | ||||
| #define MXC_NFC_V2_1 | ||||
| #define is_mxc_nfc_1()		0 | ||||
| #define is_mxc_nfc_21()		1 | ||||
| #else | ||||
| #warning "MXC NFC version not defined" | ||||
| #error "MXC NFC implementation not supported" | ||||
| #endif | ||||
| 
 | ||||
| #if defined(MXC_NFC_V1) | ||||
| #define NAND_MXC_NR_BUFS		4 | ||||
| #define NAND_MXC_SPARE_BUF_SIZE		16 | ||||
| #define NAND_MXC_REG_OFFSET		0xe00 | ||||
| #define NAND_MXC_2K_MULTI_CYCLE		1 | ||||
| #elif defined(MXC_NFC_V1_1) | ||||
| #define NAND_MXC_2K_MULTI_CYCLE | ||||
| #elif defined(MXC_NFC_V2_1) | ||||
| #define NAND_MXC_NR_BUFS		8 | ||||
| #define NAND_MXC_SPARE_BUF_SIZE		64 | ||||
| #define NAND_MXC_REG_OFFSET		0x1e00 | ||||
| #else | ||||
| #error "define CONFIG_NAND_MXC_VXXX to use the mxc spl_nand driver" | ||||
| #endif | ||||
| 
 | ||||
| struct fsl_nfc_regs { | ||||
| 	u32 main_area[NAND_MXC_NR_BUFS][512/4]; | ||||
| 	u32 spare_area[NAND_MXC_NR_BUFS][NAND_MXC_SPARE_BUF_SIZE/4]; | ||||
| 	u8 main_area[NAND_MXC_NR_BUFS][0x200]; | ||||
| 	u8 spare_area[NAND_MXC_NR_BUFS][NAND_MXC_SPARE_BUF_SIZE]; | ||||
| 	/*
 | ||||
| 	 * reserved size is offset of nfc registers | ||||
| 	 * minus total main and spare sizes | ||||
|  | @ -74,44 +73,43 @@ struct fsl_nfc_regs { | |||
| 	u8 reserved1[NAND_MXC_REG_OFFSET | ||||
| 		- NAND_MXC_NR_BUFS * (512 + NAND_MXC_SPARE_BUF_SIZE)]; | ||||
| #if defined(MXC_NFC_V1) | ||||
| 	u16 bufsiz; | ||||
| 	u16 buf_size; | ||||
| 	u16 reserved2; | ||||
| 	u16 buffer_address; | ||||
| 	u16 flash_add; | ||||
| 	u16 buf_addr; | ||||
| 	u16 flash_addr; | ||||
| 	u16 flash_cmd; | ||||
| 	u16 configuration; | ||||
| 	u16 config; | ||||
| 	u16 ecc_status_result; | ||||
| 	u16 ecc_rslt_main_area; | ||||
| 	u16 ecc_rslt_spare_area; | ||||
| 	u16 nf_wr_prot; | ||||
| 	u16 unlock_start_blk_add; | ||||
| 	u16 unlock_end_blk_add; | ||||
| 	u16 nand_flash_wr_pr_st; | ||||
| 	u16 nand_flash_config1; | ||||
| 	u16 nand_flash_config2; | ||||
| #elif defined(MXC_NFC_V1_1) | ||||
| 	u16 rsltmain_area; | ||||
| 	u16 rsltspare_area; | ||||
| 	u16 wrprot; | ||||
| 	u16 unlockstart_blkaddr; | ||||
| 	u16 unlockend_blkaddr; | ||||
| 	u16 nf_wrprst; | ||||
| 	u16 config1; | ||||
| 	u16 config2; | ||||
| #elif defined(MXC_NFC_V2_1) | ||||
| 	u16 reserved2[2]; | ||||
| 	u16 buffer_address; | ||||
| 	u16 flash_add; | ||||
| 	u16 buf_addr; | ||||
| 	u16 flash_addr; | ||||
| 	u16 flash_cmd; | ||||
| 	u16 configuration; | ||||
| 	u16 ecc_status_result; | ||||
| 	u16 ecc_status_result2; | ||||
| 	u16 config; | ||||
| 	u32 ecc_status_result; | ||||
| 	u16 spare_area_size; | ||||
| 	u16 nf_wr_prot; | ||||
| 	u16 wrprot; | ||||
| 	u16 reserved3[2]; | ||||
| 	u16 nand_flash_wr_pr_st; | ||||
| 	u16 nand_flash_config1; | ||||
| 	u16 nand_flash_config2; | ||||
| 	u16 nf_wrprst; | ||||
| 	u16 config1; | ||||
| 	u16 config2; | ||||
| 	u16 reserved4; | ||||
| 	u16 unlock_start_blk_add0; | ||||
| 	u16 unlock_end_blk_add0; | ||||
| 	u16 unlock_start_blk_add1; | ||||
| 	u16 unlock_end_blk_add1; | ||||
| 	u16 unlock_start_blk_add2; | ||||
| 	u16 unlock_end_blk_add2; | ||||
| 	u16 unlock_start_blk_add3; | ||||
| 	u16 unlock_end_blk_add3; | ||||
| 	u16 unlockstart_blkaddr; | ||||
| 	u16 unlockend_blkaddr; | ||||
| 	u16 unlockstart_blkaddr1; | ||||
| 	u16 unlockend_blkaddr1; | ||||
| 	u16 unlockstart_blkaddr2; | ||||
| 	u16 unlockend_blkaddr2; | ||||
| 	u16 unlockstart_blkaddr3; | ||||
| 	u16 unlockend_blkaddr3; | ||||
| #endif | ||||
| }; | ||||
| 
 | ||||
|  | @ -157,7 +155,7 @@ struct fsl_nfc_regs { | |||
|  */ | ||||
| #define NFC_INT		0x8000 | ||||
| 
 | ||||
| #ifdef MXC_NFC_V1_1 | ||||
| #ifdef MXC_NFC_V2_1 | ||||
| #define NFC_4_8N_ECC	(1 << 0) | ||||
| #endif | ||||
| #define NFC_SP_EN	(1 << 2) | ||||
|  | @ -167,5 +165,6 @@ struct fsl_nfc_regs { | |||
| #define NFC_RST		(1 << 6) | ||||
| #define NFC_CE		(1 << 7) | ||||
| #define NFC_ONE_CYCLE	(1 << 8) | ||||
| #define NFC_FP_INT	(1 << 11) | ||||
| 
 | ||||
| #endif /* __FSL_NFC_H */ | ||||
|  |  | |||
|  | @ -85,8 +85,10 @@ extern void nand_wait_ready(struct mtd_info *mtd); | |||
| #define NAND_CMD_RESET		0xff | ||||
| 
 | ||||
| #define NAND_CMD_LOCK		0x2a | ||||
| #define NAND_CMD_LOCK_TIGHT	0x2c | ||||
| #define NAND_CMD_UNLOCK1	0x23 | ||||
| #define NAND_CMD_UNLOCK2	0x24 | ||||
| #define NAND_CMD_LOCK_STATUS	0x7a | ||||
| 
 | ||||
| /* Extended commands for large page devices */ | ||||
| #define NAND_CMD_READSTART	0x30 | ||||
|  | @ -205,9 +207,6 @@ typedef enum { | |||
| #define NAND_SUBPAGE_READ(chip) ((chip->ecc.mode == NAND_ECC_SOFT) \ | ||||
| 					&& (chip->page_shift > 9)) | ||||
| 
 | ||||
| /* Mask to zero out the chip options, which come from the id table */ | ||||
| #define NAND_CHIPOPTIONS_MSK	(0x0000ffff & ~NAND_NO_AUTOINCR) | ||||
| 
 | ||||
| /* Non chip related options */ | ||||
| /*
 | ||||
|  * Use a flash based bad block table. OOB identifier is saved in OOB area. | ||||
|  |  | |||
|  | @ -141,11 +141,11 @@ int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, | |||
| int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts); | ||||
| 
 | ||||
| #define NAND_LOCK_STATUS_TIGHT	0x01 | ||||
| #define NAND_LOCK_STATUS_LOCK	0x02 | ||||
| #define NAND_LOCK_STATUS_UNLOCK 0x04 | ||||
| 
 | ||||
| int nand_lock( nand_info_t *meminfo, int tight ); | ||||
| int nand_unlock( nand_info_t *meminfo, ulong start, ulong length ); | ||||
| int nand_lock(nand_info_t *meminfo, int tight); | ||||
| int nand_unlock(nand_info_t *meminfo, loff_t start, size_t length, | ||||
| 	int allexcept); | ||||
| int nand_get_lock_status(nand_info_t *meminfo, loff_t offset); | ||||
| 
 | ||||
| int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst); | ||||
|  |  | |||
|  | @ -36,50 +36,58 @@ static void nfc_wait_ready(void) | |||
| { | ||||
| 	uint32_t tmp; | ||||
| 
 | ||||
| 	while (!(readw(&nfc->nand_flash_config2) & NFC_INT)) | ||||
| 	while (!(readw(&nfc->config2) & NFC_INT)) | ||||
| 		; | ||||
| 
 | ||||
| 	/* Reset interrupt flag */ | ||||
| 	tmp = readw(&nfc->nand_flash_config2); | ||||
| 	tmp = readw(&nfc->config2); | ||||
| 	tmp &= ~NFC_INT; | ||||
| 	writew(tmp, &nfc->nand_flash_config2); | ||||
| 	writew(tmp, &nfc->config2); | ||||
| } | ||||
| 
 | ||||
| void nfc_nand_init(void) | ||||
| static void nfc_nand_init(void) | ||||
| { | ||||
| #if defined(MXC_NFC_V1_1) | ||||
| 	int ecc_per_page  = CONFIG_SYS_NAND_PAGE_SIZE / 512; | ||||
| #if defined(MXC_NFC_V2_1) | ||||
| 	int ecc_per_page = CONFIG_SYS_NAND_PAGE_SIZE / 512; | ||||
| 	int config1; | ||||
| 
 | ||||
| 	writew(CONFIG_SYS_NAND_SPARE_SIZE / 2, &nfc->spare_area_size); | ||||
| 
 | ||||
| 	/* unlocking RAM Buff */ | ||||
| 	writew(0x2, &nfc->configuration); | ||||
| 	writew(0x2, &nfc->config); | ||||
| 
 | ||||
| 	/* hardware ECC checking and correct */ | ||||
| 	config1 = readw(&nfc->nand_flash_config1) | NFC_ECC_EN | 0x800; | ||||
| 	config1 = readw(&nfc->config1) | NFC_ECC_EN | NFC_INT_MSK | | ||||
| 			NFC_ONE_CYCLE | NFC_FP_INT; | ||||
| 	/*
 | ||||
| 	 * if spare size is larger that 16 bytes per 512 byte hunk | ||||
| 	 * then use 8 symbol correction instead of 4 | ||||
| 	 */ | ||||
| 	if ((CONFIG_SYS_NAND_SPARE_SIZE / ecc_per_page) > 16) | ||||
| 	if (CONFIG_SYS_NAND_SPARE_SIZE / ecc_per_page > 16) | ||||
| 		config1 &= ~NFC_4_8N_ECC; | ||||
| 	else | ||||
| 		config1 |= NFC_4_8N_ECC; | ||||
| 	writew(config1, &nfc->nand_flash_config1); | ||||
| 	writew(config1, &nfc->config1); | ||||
| #elif defined(MXC_NFC_V1) | ||||
| 	/* unlocking RAM Buff */ | ||||
| 	writew(0x2, &nfc->configuration); | ||||
| 	writew(0x2, &nfc->config); | ||||
| 
 | ||||
| 	/* hardware ECC checking and correct */ | ||||
| 	writew(NFC_ECC_EN, &nfc->nand_flash_config1); | ||||
| 	writew(NFC_ECC_EN | NFC_INT_MSK, &nfc->config1); | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| static void nfc_nand_command(unsigned short command) | ||||
| { | ||||
| 	writew(command, &nfc->flash_cmd); | ||||
| 	writew(NFC_CMD, &nfc->nand_flash_config2); | ||||
| 	writew(NFC_CMD, &nfc->config2); | ||||
| 	nfc_wait_ready(); | ||||
| } | ||||
| 
 | ||||
| static void nfc_nand_address(unsigned short address) | ||||
| { | ||||
| 	writew(address, &nfc->flash_addr); | ||||
| 	writew(NFC_ADDR, &nfc->config2); | ||||
| 	nfc_wait_ready(); | ||||
| } | ||||
| 
 | ||||
|  | @ -87,58 +95,43 @@ static void nfc_nand_page_address(unsigned int page_address) | |||
| { | ||||
| 	unsigned int page_count; | ||||
| 
 | ||||
| 	writew(0x00, &nfc->flash_add); | ||||
| 	writew(NFC_ADDR, &nfc->nand_flash_config2); | ||||
| 	nfc_wait_ready(); | ||||
| 	nfc_nand_address(0x00); | ||||
| 
 | ||||
| 	/* code only for large page flash */ | ||||
| 	if (CONFIG_SYS_NAND_PAGE_SIZE > 512) { | ||||
| 		writew(0x00, &nfc->flash_add); | ||||
| 		writew(NFC_ADDR, &nfc->nand_flash_config2); | ||||
| 		nfc_wait_ready(); | ||||
| 	} | ||||
| 	if (CONFIG_SYS_NAND_PAGE_SIZE > 512) | ||||
| 		nfc_nand_address(0x00); | ||||
| 
 | ||||
| 	page_count = CONFIG_SYS_NAND_SIZE / CONFIG_SYS_NAND_PAGE_SIZE; | ||||
| 
 | ||||
| 	if (page_address <= page_count) { | ||||
| 		page_count--; /* transform 0x01000000 to 0x00ffffff */ | ||||
| 		do { | ||||
| 			writew(page_address & 0xff, &nfc->flash_add); | ||||
| 			writew(NFC_ADDR, &nfc->nand_flash_config2); | ||||
| 			nfc_wait_ready(); | ||||
| 			nfc_nand_address(page_address & 0xff); | ||||
| 			page_address = page_address >> 8; | ||||
| 			page_count = page_count >> 8; | ||||
| 		} while (page_count); | ||||
| 	} | ||||
| 
 | ||||
| 	writew(0x00, &nfc->flash_add); | ||||
| 	writew(NFC_ADDR, &nfc->nand_flash_config2); | ||||
| 	nfc_wait_ready(); | ||||
| 	nfc_nand_address(0x00); | ||||
| } | ||||
| 
 | ||||
| static void nfc_nand_data_output(void) | ||||
| { | ||||
| 	int config1 = readw(&nfc->nand_flash_config1); | ||||
| #ifdef NAND_MXC_2K_MULTI_CYCLE | ||||
| 	int i; | ||||
| #endif | ||||
| 
 | ||||
| 	config1 |= NFC_ECC_EN | NFC_INT_MSK; | ||||
| 	writew(config1, &nfc->nand_flash_config1); | ||||
| 	writew(0, &nfc->buffer_address); | ||||
| 	writew(NFC_OUTPUT, &nfc->nand_flash_config2); | ||||
| 	writew(0, &nfc->buf_addr); | ||||
| 	writew(NFC_OUTPUT, &nfc->config2); | ||||
| 	nfc_wait_ready(); | ||||
| #ifdef NAND_MXC_2K_MULTI_CYCLE | ||||
| 	/*
 | ||||
| 	 * This NAND controller requires multiple input commands | ||||
| 	 * for pages larger than 512 bytes. | ||||
| 	 */ | ||||
| 	for (i = 1; i < (CONFIG_SYS_NAND_PAGE_SIZE / 512); i++) { | ||||
| 		config1 = readw(&nfc->nand_flash_config1); | ||||
| 		config1 |= NFC_ECC_EN | NFC_INT_MSK; | ||||
| 		writew(config1, &nfc->nand_flash_config1); | ||||
| 		writew(i, &nfc->buffer_address); | ||||
| 		writew(NFC_OUTPUT, &nfc->nand_flash_config2); | ||||
| 	for (i = 1; i < CONFIG_SYS_NAND_PAGE_SIZE / 512; i++) { | ||||
| 		writew(i, &nfc->buf_addr); | ||||
| 		writew(NFC_OUTPUT, &nfc->config2); | ||||
| 		nfc_wait_ready(); | ||||
| 	} | ||||
| #endif | ||||
|  | @ -146,7 +139,35 @@ static void nfc_nand_data_output(void) | |||
| 
 | ||||
| static int nfc_nand_check_ecc(void) | ||||
| { | ||||
| 	return readw(&nfc->ecc_status_result); | ||||
| #if defined(MXC_NFC_V1) | ||||
| 	u16 ecc_status = readw(&nfc->ecc_status_result); | ||||
| 	return (ecc_status & 0x3) == 2 || (ecc_status >> 2) == 2; | ||||
| #elif defined(MXC_NFC_V2_1) | ||||
| 	u32 ecc_status = readl(&nfc->ecc_status_result); | ||||
| 	int ecc_per_page = CONFIG_SYS_NAND_PAGE_SIZE / 512; | ||||
| 	int err_limit = CONFIG_SYS_NAND_SPARE_SIZE / ecc_per_page > 16 ? 8 : 4; | ||||
| 	int subpages = CONFIG_SYS_NAND_PAGE_SIZE / 512; | ||||
| 
 | ||||
| 	do { | ||||
| 		if ((ecc_status & 0xf) > err_limit) | ||||
| 			return 1; | ||||
| 		ecc_status >>= 4; | ||||
| 	} while (--subpages); | ||||
| 
 | ||||
| 	return 0; | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| static void nfc_nand_read_page(unsigned int page_address) | ||||
| { | ||||
| 	writew(0, &nfc->buf_addr); /* read in first 0 buffer */ | ||||
| 	nfc_nand_command(NAND_CMD_READ0); | ||||
| 	nfc_nand_page_address(page_address); | ||||
| 
 | ||||
| 	if (CONFIG_SYS_NAND_PAGE_SIZE > 512) | ||||
| 		nfc_nand_command(NAND_CMD_READSTART); | ||||
| 
 | ||||
| 	nfc_nand_data_output(); /* fill the main buffer 0 */ | ||||
| } | ||||
| 
 | ||||
| static int nfc_read_page(unsigned int page_address, unsigned char *buf) | ||||
|  | @ -155,23 +176,16 @@ static int nfc_read_page(unsigned int page_address, unsigned char *buf) | |||
| 	u32 *src; | ||||
| 	u32 *dst; | ||||
| 
 | ||||
| 	writew(0, &nfc->buffer_address); /* read in first 0 buffer */ | ||||
| 	nfc_nand_command(NAND_CMD_READ0); | ||||
| 	nfc_nand_page_address(page_address); | ||||
| 
 | ||||
| 	if (CONFIG_SYS_NAND_PAGE_SIZE > 512) | ||||
| 		nfc_nand_command(NAND_CMD_READSTART); | ||||
| 
 | ||||
| 	nfc_nand_data_output(); /* fill the main buffer 0 */ | ||||
| 	nfc_nand_read_page(page_address); | ||||
| 
 | ||||
| 	if (nfc_nand_check_ecc()) | ||||
| 		return -1; | ||||
| 
 | ||||
| 	src = &nfc->main_area[0][0]; | ||||
| 	src = (u32 *)&nfc->main_area[0][0]; | ||||
| 	dst = (u32 *)buf; | ||||
| 
 | ||||
| 	/* main copy loop from NAND-buffer to SDRAM memory */ | ||||
| 	for (i = 0; i < (CONFIG_SYS_NAND_PAGE_SIZE / 4); i++) { | ||||
| 	for (i = 0; i < CONFIG_SYS_NAND_PAGE_SIZE / 4; i++) { | ||||
| 		writel(readl(src), dst); | ||||
| 		src++; | ||||
| 		dst++; | ||||
|  | @ -188,16 +202,9 @@ static int is_badblock(int pagenumber) | |||
| 
 | ||||
| 	/* Check the first two pages for bad block markers */ | ||||
| 	for (page = pagenumber; page < pagenumber + 2; page++) { | ||||
| 		writew(0, &nfc->buffer_address); /* read in first 0 buffer */ | ||||
| 		nfc_nand_command(NAND_CMD_READ0); | ||||
| 		nfc_nand_page_address(page); | ||||
| 		nfc_nand_read_page(page); | ||||
| 
 | ||||
| 		if (CONFIG_SYS_NAND_PAGE_SIZE > 512) | ||||
| 			nfc_nand_command(NAND_CMD_READSTART); | ||||
| 
 | ||||
| 		nfc_nand_data_output(); /* fill the main buffer 0 */ | ||||
| 
 | ||||
| 		src = &nfc->spare_area[0][0]; | ||||
| 		src = (u32 *)&nfc->spare_area[0][0]; | ||||
| 
 | ||||
| 		/*
 | ||||
| 		 * IMPORTANT NOTE: The nand flash controller uses a non- | ||||
|  | @ -230,7 +237,7 @@ static int nand_load(unsigned int from, unsigned int size, unsigned char *buf) | |||
| 	page = from / CONFIG_SYS_NAND_PAGE_SIZE; | ||||
| 	i = 0; | ||||
| 
 | ||||
| 	while (i < (size / CONFIG_SYS_NAND_PAGE_SIZE)) { | ||||
| 	while (i < size / CONFIG_SYS_NAND_PAGE_SIZE) { | ||||
| 		if (nfc_read_page(page, buf) < 0) | ||||
| 			return -1; | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue