diff options
| author | kaloz <kaloz@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2012-05-01 07:00:17 +0000 | 
|---|---|---|
| committer | kaloz <kaloz@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2012-05-01 07:00:17 +0000 | 
| commit | 7e7649baa9de9d592a76e150970e3079d7610138 (patch) | |
| tree | 7e3c3b52269e3c7564c6a88d67dc4ea6219b041c /target/linux/coldfire/patches/016-Add-nand-driver-support-for-M54418TWR-board.patch | |
| parent | 7877ca154f130fe0c83a5f151320c3ce902195d1 (diff) | |
[coldfire]: switch to 2.6.38
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@31546 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'target/linux/coldfire/patches/016-Add-nand-driver-support-for-M54418TWR-board.patch')
| -rw-r--r-- | target/linux/coldfire/patches/016-Add-nand-driver-support-for-M54418TWR-board.patch | 1381 | 
1 files changed, 1381 insertions, 0 deletions
diff --git a/target/linux/coldfire/patches/016-Add-nand-driver-support-for-M54418TWR-board.patch b/target/linux/coldfire/patches/016-Add-nand-driver-support-for-M54418TWR-board.patch new file mode 100644 index 000000000..e495ab81c --- /dev/null +++ b/target/linux/coldfire/patches/016-Add-nand-driver-support-for-M54418TWR-board.patch @@ -0,0 +1,1381 @@ +From 6a5c2427d53c24a30f28b8061b2cda4edad37f58 Mon Sep 17 00:00:00 2001 +From: Alison Wang <b18965@freescale.com> +Date: Thu, 4 Aug 2011 09:59:43 +0800 +Subject: [PATCH 16/52] Add nand driver support for M54418TWR board + +Disable hw ECC for erase block aligned pages. + +On the erase block, there's always have clean marker for jffs2, +The NFC ECC provide a fake correction on the erase block when +there're clean marker and adjust the bits on the fly when reading back. + +Disable the hw ECC on erase block aligned pages is a workaround +for jffs2 on the NAND. + +Signed-off-by: Alison Wang <b18965@freescale.com> +--- + arch/m68k/include/asm/fsl_nfc.h |  330 +++++++++++++ + drivers/mtd/nand/Kconfig        |    7 + + drivers/mtd/nand/Makefile       |    1 + + drivers/mtd/nand/fsl_nfc.c      |  995 +++++++++++++++++++++++++++++++++++++++ + 4 files changed, 1333 insertions(+), 0 deletions(-) + create mode 100644 arch/m68k/include/asm/fsl_nfc.h + create mode 100644 drivers/mtd/nand/fsl_nfc.c + +--- /dev/null ++++ b/arch/m68k/include/asm/fsl_nfc.h +@@ -0,0 +1,330 @@ ++/* ++ * Copyright (C) 2009-2011 Freescale Semiconductor, Inc. All Rights Reserved. ++ * ++ * Author: Shaohui Xie <b21989@freescale.com> ++ * ++ * Description: ++ * MPC5125/M54418TWR Nand driver. ++ * ++ * This is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ */ ++ ++#ifndef MPC5125_NFC_H ++#define MPC5125_NFC_H ++ ++ ++/* NFC PAD Define */ ++#define PAD_NFC_IO			PAD_FUNC0 ++#define PAD_NFC_ALE			PAD_FUNC0 ++#define PAD_NFC_CLE			PAD_FUNC0 ++#define PAD_NFC_WE			PAD_FUNC0 ++#define PAD_NFC_RE			PAD_FUNC0 ++#define PAD_NFC_CE0			PAD_FUNC0 ++#define PAD_NFC_CE1			PAD_FUNC1 ++#define PAD_NFC_CE2			PAD_FUNC2 ++#define PAD_NFC_CE3			PAD_FUNC2 ++#define PAD_NFC_RB0			PAD_FUNC0 ++#define PAD_NFC_RB1			PAD_FUNC2 ++#define PAD_NFC_RB2			PAD_FUNC2 ++#define PAD_NFC_RB3			PAD_FUNC2 ++ ++/* NFC Control PAD Define */ ++#define BALL_NFC_CE0			IOCTL_NFC_CE0_B ++#define BALL_NFC_CE1			IOCTL_SDHC1_CLK ++#define BALL_NFC_CE2			IOCTL_PSC1_4 ++#define BALL_NFC_CE3			IOCTL_J1850_TX ++#define BALL_NFC_RB0			IOCTL_NFC_RB ++#define BALL_NFC_RB1			IOCTL_FEC1_TXD_0 ++#define BALL_NFC_RB2			IOCTL_PSC1_3 ++#define BALL_NFC_RB3			IOCTL_J1850_RX ++#define BALL_NFC_ALE			IOCTL_EMB_AD19 ++#define BALL_NFC_CLE			IOCTL_EMB_AD18 ++#define BALL_NFC_WE			IOCTL_EMB_AD16 ++#define BALL_NFC_RE			IOCTL_EMB_AD17 ++ ++/* NFC IO Pad Define */ ++#define BALL_NFC_IO0			IOCTL_EMB_AD00 ++#define BALL_NFC_IO1			IOCTL_EMB_AD01 ++#define BALL_NFC_IO2			IOCTL_EMB_AD02 ++#define BALL_NFC_IO3			IOCTL_EMB_AD03 ++#define BALL_NFC_IO4			IOCTL_EMB_AD04 ++#define BALL_NFC_IO5			IOCTL_EMB_AD05 ++#define BALL_NFC_IO6			IOCTL_EMB_AD06 ++#define BALL_NFC_IO7			IOCTL_EMB_AD07 ++ ++/* Addresses for NFC MAIN RAM BUFFER areas */ ++#define NFC_MAIN_AREA(n)		((n) *  0x1000) ++ ++/* Addresses for NFC SPARE BUFFER areas */ ++#define NFC_SPARE_BUFFERS		8 ++#define NFC_SPARE_LEN			0x10 ++#define NFC_SPARE_AREA(n)		(0x800 + ((n) * NFC_SPARE_LEN)) ++ ++#define PAGE_2K				0x0800 ++#define PAGE_64				0x0040 ++ ++/* MPC5125 NFC registers */ ++/* Typical Flash Commands */ ++#define READ_PAGE_CMD_CODE		0x7EE0 ++#define PROGRAM_PAGE_CMD_CODE		0x7FC0 ++#define ERASE_CMD_CODE			0x4EC0 ++#define READ_ID_CMD_CODE		0x4804 ++#define RESET_CMD_CODE			0x4040 ++#define DMA_PROGRAM_PAGE_CMD_CODE	0xFFC8 ++#define RANDOM_IN_CMD_CODE		0x7140 ++#define RANDOM_OUT_CMD_CODE		0x70E0 ++#define STATUS_READ_CMD_CODE		0x4068 ++ ++#define PAGE_READ_CMD_BYTE1		0x00 ++#define PAGE_READ_CMD_BYTE2		0x30 ++#define PROGRAM_PAGE_CMD_BYTE1		0x80 ++#define PROGRAM_PAGE_CMD_BYTE2		0x10 ++#define READ_STATUS_CMD_BYTE		0x70 ++#define ERASE_CMD_BYTE1			0x60 ++#define ERASE_CMD_BYTE2			0xD0 ++#define READ_ID_CMD_BYTE		0x90 ++#define RESET_CMD_BYTE			0xFF ++#define RANDOM_OUT_CMD_BYTE1		0x05 ++#define RANDOM_OUT_CMD_BYTE2		0xE0 ++ ++/* NFC ECC mode define */ ++#define ECC_BYPASS			0x0 ++#define ECC_8_BYTE			0x1 ++#define ECC_12_BYTE			0x2 ++#define ECC_15_BYTE			0x3 ++#define ECC_23_BYTE			0x4 ++#define ECC_30_BYTE			0x5 ++#define ECC_45_BYTE			0x6 ++#define ECC_60_BYTE			0x7 ++#define ECC_ERROR			1 ++#define ECC_RIGHT			0 ++ ++/***************** Module-Relative Register Offsets *************************/ ++#define NFC_SRAM_BUFFER			0x0000 ++#define NFC_FLASH_CMD1			0x3F00 ++#define NFC_FLASH_CMD2			0x3F04 ++#define NFC_COL_ADDR			0x3F08 ++#define NFC_ROW_ADDR			0x3F0c ++#define NFC_FLASH_COMMAND_REPEAT	0x3F10 ++#define NFC_ROW_ADDR_INC		0x3F14 ++#define NFC_FLASH_STATUS1		0x3F18 ++#define NFC_FLASH_STATUS2		0x3F1c ++#define NFC_DMA1_ADDR			0x3F20 ++#define NFC_DMA2_ADDR			0x3F34 ++#define NFC_DMA_CONFIG			0x3F24 ++#define NFC_CACHE_SWAP			0x3F28 ++#define NFC_SECTOR_SIZE			0x3F2c ++#define NFC_FLASH_CONFIG		0x3F30 ++#define NFC_IRQ_STATUS			0x3F38 ++ ++/***************** Module-Relative Register Reset Value *********************/ ++#define NFC_SRAM_BUFFER_RSTVAL			0x00000000 ++#define NFC_FLASH_CMD1_RSTVAL			0x30FF0000 ++#define NFC_FLASH_CMD2_RSTVAL			0x007EE000 ++#define NFC_COL_ADDR_RSTVAL			0x00000000 ++#define NFC_ROW_ADDR_RSTVAL			0x11000000 ++#define NFC_FLASH_COMMAND_REPEAT_RSTVAL		0x00000000 ++#define NFC_ROW_ADDR_INC_RSTVAL			0x00000001 ++#define NFC_FLASH_STATUS1_RSTVAL		0x00000000 ++#define NFC_FLASH_STATUS2_RSTVAL		0x00000000 ++#define NFC_DMA1_ADDR_RSTVAL			0x00000000 ++#define NFC_DMA2_ADDR_RSTVAL			0x00000000 ++#define NFC_DMA_CONFIG_RSTVAL			0x00000000 ++#define NFC_CACHE_SWAP_RSTVAL			0x0FFE0FFE ++#define NFC_SECTOR_SIZE_RSTVAL			0x00000420 ++#define NFC_FLASH_CONFIG_RSTVAL			0x000EA631 ++#define NFC_IRQ_STATUS_RSTVAL			0x04000000 ++ ++/***************** Module-Relative Register Mask *************************/ ++ ++/* NFC_FLASH_CMD1 Field */ ++#define CMD1_MASK				0xFFFF0000 ++#define CMD1_SHIFT				0 ++#define CMD_BYTE2_MASK				0xFF000000 ++#define CMD_BYTE2_SHIFT				24 ++#define CMD_BYTE3_MASK				0x00FF0000 ++#define CMD_BYTE3_SHIFT				16 ++ ++/* NFC_FLASH_CM2 Field */ ++#define CMD2_MASK				0xFFFFFF07 ++#define CMD2_SHIFT				0 ++#define CMD_BYTE1_MASK				0xFF000000 ++#define CMD_BYTE1_SHIFT				24 ++#define CMD_CODE_MASK				0x00FFFF00 ++#define CMD_CODE_SHIFT				8 ++#define BUFNO_MASK				0x00000006 ++#define BUFNO_SHIFT				1 ++#define BUSY_MASK				0x00000001 ++#define BUSY_SHIFT				0 ++#define START_MASK				0x00000001 ++#define START_SHIFT				0 ++ ++/* NFC_COL_ADDR Field */ ++#define COL_ADDR_MASK				0x0000FFFF ++#define COL_ADDR_SHIFT				0 ++#define COL_ADDR_COL_ADDR2_MASK			0x0000FF00 ++#define COL_ADDR_COL_ADDR2_SHIFT		8 ++#define COL_ADDR_COL_ADDR1_MASK			0x000000FF ++#define COL_ADDR_COL_ADDR1_SHIFT		0 ++ ++/* NFC_ROW_ADDR Field */ ++#define ROW_ADDR_MASK				0x00FFFFFF ++#define ROW_ADDR_SHIFT				0 ++#define ROW_ADDR_CHIP_SEL_RB_MASK		0xF0000000 ++#define ROW_ADDR_CHIP_SEL_RB_SHIFT		28 ++#define ROW_ADDR_CHIP_SEL_MASK			0x0F000000 ++#define ROW_ADDR_CHIP_SEL_SHIFT			24 ++#define ROW_ADDR_ROW_ADDR3_MASK			0x00FF0000 ++#define ROW_ADDR_ROW_ADDR3_SHIFT		16 ++#define ROW_ADDR_ROW_ADDR2_MASK			0x0000FF00 ++#define ROW_ADDR_ROW_ADDR2_SHIFT		8 ++#define ROW_ADDR_ROW_ADDR1_MASK			0x000000FF ++#define ROW_ADDR_ROW_ADDR1_SHIFT		0 ++ ++/* NFC_FLASH_COMMAND_REPEAT Field */ ++#define COMMAND_REPEAT_MASK			0x0000FFFF ++#define COMMAND_REPEAT_SHIFT			0 ++#define COMMAND_REPEAT_REPEAT_COUNT_MASK	0x0000FFFF ++#define COMMAND_REPEAT_REPEAT_COUNT_SHIFT	0 ++ ++/* NFC_ROW_ADDR_INC Field */ ++#define ROW_ADDR_INC_MASK			0x00FFFFFF ++#define ROW_ADDR_INC_SHIFT			0 ++#define ROW_ADDR_INC_ROW_ADDR3_INC_MASK		0x00FF0000 ++#define ROW_ADDR_INC_ROW_ADDR3_INC_SHIFT	16 ++#define ROW_ADDR_INC_ROW_ADDR2_INC_MASK		0x0000FF00 ++#define ROW_ADDR_INC_ROW_ADDR2_INC_SHIFT	8 ++#define ROW_ADDR_INC_ROW_ADDR1_INC_MASK		0x000000FF ++#define ROW_ADDR_INC_ROW_ADDR1_INC_SHIFT	0 ++ ++/* NFC_FLASH_STATUS1 Field */ ++#define STATUS1_MASK				0xFFFFFFFF ++#define STATUS1_SHIFT				0 ++#define STATUS1_ID_BYTE1_MASK			0xFF000000 ++#define STATUS1_ID_BYTE1_SHIFT			24 ++#define STATUS1_ID_BYTE2_MASK			0x00FF0000 ++#define STATUS1_ID_BYTE2_SHIFT			16 ++#define STATUS1_ID_BYTE3_MASK			0x0000FF00 ++#define STATUS1_ID_BYTE3_SHIFT			8 ++#define STATUS1_ID_BYTE4_MASK			0x000000FF ++#define STATUS1_ID_BYTE4_SHIFT			0 ++ ++/* NFC_FLASH_STATUS2 Field */ ++#define STATUS2_MASK				0xFF0000FF ++#define STATUS2_SHIFT				0 ++#define STATUS2_ID_BYTE5_MASK			0xFF000000 ++#define STATUS2_ID_BYTE5_SHIFT			24 ++#define STATUS_BYTE1_MASK			0x000000FF ++#define STATUS2_STATUS_BYTE1_SHIFT		0 ++ ++/* NFC_DMA1_ADDR Field */ ++#define DMA1_ADDR_MASK				0xFFFFFFFF ++#define DMA1_ADDR_SHIFT				0 ++#define DMA1_ADDR_DMA1_ADDR_MASK		0xFFFFFFFF ++#define DMA1_ADDR_DMA1_ADDR_SHIFT		0 ++ ++/* DMA2_ADDR Field */ ++#define DMA2_ADDR_MASK				0xFFFFFFFF ++#define DMA2_ADDR_SHIFT				0 ++#define DMA2_ADDR_DMA2_ADDR_MASK		0xFFFFFFFF ++#define DMA2_ADDR_DMA2_ADDR_SHIFT		0 ++ ++/* DMA_CONFIG Field */ ++#define DMA_CONFIG_MASK				0xFFFFFFFF ++#define DMA_CONFIG_SHIFT			0 ++#define DMA_CONFIG_DMA1_CNT_MASK		0xFFF00000 ++#define DMA_CONFIG_DMA1_CNT_SHIFT		20 ++#define DMA_CONFIG_DMA2_CNT_MASK		0x000FE000 ++#define DMA_CONFIG_DMA2_CNT_SHIFT		13 ++#define DMA_CONFIG_DMA2_OFFSET_MASK		0x00001FC0 ++#define DMA_CONFIG_DMA2_OFFSET_SHIFT		2 ++#define DMA_CONFIG_DMA1_ACT_MASK		0x00000002 ++#define DMA_CONFIG_DMA1_ACT_SHIFT		1 ++#define DMA_CONFIG_DMA2_ACT_MASK		0x00000001 ++#define DMA_CONFIG_DMA2_ACT_SHIFT		0 ++ ++/* NFC_CACHE_SWAP Field */ ++#define CACHE_SWAP_MASK				0x0FFE0FFE ++#define CACHE_SWAP_SHIFT			1 ++#define CACHE_SWAP_CACHE_SWAP_ADDR2_MASK	0x0FFE0000 ++#define CACHE_SWAP_CACHE_SWAP_ADDR2_SHIFT	17 ++#define CACHE_SWAP_CACHE_SWAP_ADDR1_MASK	0x00000FFE ++#define CACHE_SWAP_CACHE_SWAP_ADDR1_SHIFT	1 ++ ++/* NFC_SECTOR_SIZE Field */ ++#define SECTOR_SIZE_MASK			0x00001FFF ++#define SECTOR_SIZE_SHIFT			0 ++#define SECTOR_SIZE_SECTOR_SIZE_MASK		0x00001FFF ++#define SECTOR_SIZE_SECTOR_SIZE_SHIFT		0 ++ ++/* NFC_FLASH_CONFIG Field */ ++#define CONFIG_MASK				0xFFFFFFFF ++#define CONFIG_SHIFT				0 ++#define CONFIG_STOP_ON_WERR_MASK		0x80000000 ++#define CONFIG_STOP_ON_WERR_SHIFT		31 ++#define CONFIG_ECC_SRAM_ADDR_MASK		0x7FC00000 ++#define CONFIG_ECC_SRAM_ADDR_SHIFT		22 ++#define CONFIG_ECC_SRAM_REQ_MASK		0x00200000 ++#define CONFIG_ECC_SRAM_REQ_SHIFT		21 ++#define CONFIG_DMA_REQ_MASK			0x00100000 ++#define CONFIG_DMA_REQ_SHIFT			20 ++#define CONFIG_ECC_MODE_MASK			0x000E0000 ++#define CONFIG_ECC_MODE_SHIFT			17 ++#define CONFIG_FAST_FLASH_MASK			0x00010000 ++#define CONFIG_FAST_FLASH_SHIFT			16 ++#define CONFIG_ID_COUNT_MASK			0x0000E000 ++#define CONFIG_ID_COUNT_SHIFT			13 ++#define CONFIG_CMD_TIMEOUT_MASK			0x00001F00 ++#define CONFIG_CMD_TIMEOUT_SHIFT		8 ++#define CONFIG_16BIT_MASK			0x00000080 ++#define CONFIG_16BIT_SHIFT			7 ++#define CONFIG_BOOT_MODE_MASK			0x00000040 ++#define CONFIG_BOOT_MODE_SHIFT			6 ++#define CONFIG_ADDR_AUTO_INCR_MASK		0x00000020 ++#define CONFIG_ADDR_AUTO_INCR_SHIFT		5 ++#define CONFIG_BUFNO_AUTO_INCR_MASK		0x00000010 ++#define CONFIG_BUFNO_AUTO_INCR_SHIFT		4 ++#define CONFIG_PAGE_CNT_MASK			0x0000000F ++#define CONFIG_PAGE_CNT_SHIFT			0 ++ ++/* NFC_IRQ_STATUS Field */ ++#define MASK					0xEFFC003F ++#define SHIFT					0 ++#define WERR_IRQ_MASK				0x80000000 ++#define WERR_IRQ_SHIFT				31 ++#define CMD_DONE_IRQ_MASK			0x40000000 ++#define CMD_DONE_IRQ_SHIFT			30 ++#define IDLE_IRQ_MASK				0x20000000 ++#define IDLE_IRQ_SHIFT				29 ++#define WERR_STATUS_MASK			0x08000000 ++#define WERR_STATUS_SHIFT			27 ++#define FLASH_CMD_BUSY_MASK			0x04000000 ++#define FLASH_CMD_BUSY_SHIFT			26 ++#define RESIDUE_BUSY_MASK			0x02000000 ++#define RESIDUE_BUSY_SHIFT			25 ++#define ECC_BUSY_MASK				0x01000000 ++#define ECC_BUSY_SHIFT				24 ++#define DMA_BUSY_MASK				0x00800000 ++#define DMA_BUSY_SHIFT				23 ++#define WERR_EN_MASK				0x00400000 ++#define WERR_EN_SHIFT				22 ++#define CMD_DONE_EN_MASK			0x00200000 ++#define CMD_DONE_EN_SHIFT			21 ++#define IDLE_EN_MASK				0x00100000 ++#define IDLE_EN_SHIFT				20 ++#define WERR_CLEAR_MASK				0x00080000 ++#define WERR_CLEAR_SHIFT			19 ++#define CMD_DONE_CLEAR_MASK			0x00040000 ++#define CMD_DONE_CLEAR_SHIFT			18 ++#define IDLE_CLEAR_MASK				0x00020000 ++#define IDLE_CLEAR_SHIFT			17 ++#define RESIDUE_BUFF_NO_MASK			0x00000030 ++#define RESIDUE_BUFF_NO_SHIFT			4 ++#define ECC_BUFF_NO_MASK			0x000000C0 ++#define ECC_BUFF_NO_SHIFT			2 ++#define DMA_BUFF_NO_MASK			0x00000003 ++ ++#endif /* MPC5125_NFC_H */ +--- a/drivers/mtd/nand/Kconfig ++++ b/drivers/mtd/nand/Kconfig +@@ -474,6 +474,13 @@ config MTD_NAND_MPC5121_NFC + 	  This enables the driver for the NAND flash controller on the + 	  MPC5121 SoC. +  ++config MTD_NAND_FSL_NFC ++	tristate "Support for NAND on Freescale ColdFire NFC" ++	depends on MTD_NAND && M5441X ++	help ++	  Enables support for NAND Flash chips wired onto Freescale PowerPC ++	  processor localbus with User-Programmable Machine support. ++ + config MTD_NAND_MXC + 	tristate "MXC NAND support" + 	depends on ARCH_MX2 || ARCH_MX25 || ARCH_MX3 || ARCH_MX51 +--- a/drivers/mtd/nand/Makefile ++++ b/drivers/mtd/nand/Makefile +@@ -38,6 +38,7 @@ obj-$(CONFIG_MTD_NAND_PASEMI)		+= pasemi + obj-$(CONFIG_MTD_NAND_ORION)		+= orion_nand.o + obj-$(CONFIG_MTD_NAND_FSL_ELBC)		+= fsl_elbc_nand.o + obj-$(CONFIG_MTD_NAND_FSL_UPM)		+= fsl_upm.o ++obj-$(CONFIG_MTD_NAND_FSL_NFC)		+= fsl_nfc.o + obj-$(CONFIG_MTD_NAND_SH_FLCTL)		+= sh_flctl.o + obj-$(CONFIG_MTD_NAND_MXC)		+= mxc_nand.o + obj-$(CONFIG_MTD_NAND_SOCRATES)		+= socrates_nand.o +--- /dev/null ++++ b/drivers/mtd/nand/fsl_nfc.c +@@ -0,0 +1,995 @@ ++/* ++ * Copyright (C) 2009-2011 Freescale Semiconductor, Inc. All Rights Reserved. ++ * ++ * Author: Shaohui Xie <b21989@freescale.com> ++ *	   Jason Jin <Jason.jin@freescale.com> ++ * ++ * Description: ++ * MPC5125 Nand driver. ++ * Jason ported to M54418TWR. ++ * ++ * Based on original driver mpc5121_nfc.c. ++ * ++ * This is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ */ ++ ++#include <linux/module.h> ++#include <linux/clk.h> ++#include <linux/delay.h> ++#include <linux/init.h> ++#include <linux/interrupt.h> ++#include <linux/io.h> ++#include <linux/mtd/mtd.h> ++#include <linux/mtd/nand.h> ++#include <linux/mtd/partitions.h> ++#include <linux/platform_device.h> ++#include <linux/slab.h> ++#include <asm/fsl_nfc.h> ++#include <asm/mcfsim.h> ++ ++#define	DRV_NAME		"fsl_nfc" ++#define	DRV_VERSION		"0.5" ++ ++/* Timeouts */ ++#define NFC_RESET_TIMEOUT	1000		/* 1 ms */ ++#define NFC_TIMEOUT		(HZ) ++ ++ ++#define ECC_SRAM_ADDR	(0x840 >> 3) ++#define ECC_STATUS_MASK	0x80 ++#define ECC_ERR_COUNT	0x3F ++ ++#define MIN(x, y)		((x < y) ? x : y) ++ ++#ifdef CONFIG_MTD_NAND_FSL_NFC_SWECC ++static int hardware_ecc; ++#else ++static int hardware_ecc = 1; ++#endif ++ ++ ++struct fsl_nfc_prv { ++	struct mtd_info		mtd; ++	struct nand_chip	chip; ++	int			irq; ++	void __iomem		*regs; ++	struct clk		*clk; ++	wait_queue_head_t	irq_waitq; ++	uint			column; ++	int			spareonly; ++	int			page; ++}; ++ ++static int get_status; ++static int get_id; ++ ++static u8 bbt_pattern[] = {'B', 'b', 't', '0' }; ++static u8 mirror_pattern[] = {'1', 't', 'b', 'B' }; ++ ++static struct nand_bbt_descr bbt_main_descr = { ++	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | ++		   NAND_BBT_2BIT | NAND_BBT_VERSION, ++	.offs =	11, ++	.len = 4, ++	.veroffs = 15, ++	.maxblocks = 4, ++	.pattern = bbt_pattern, ++}; ++ ++static struct nand_bbt_descr bbt_mirror_descr = { ++	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | ++		   NAND_BBT_2BIT | NAND_BBT_VERSION, ++	.offs =	11, ++	.len = 4, ++	.veroffs = 15, ++	.maxblocks = 4, ++	.pattern = mirror_pattern, ++}; ++ ++ ++#ifdef CONFIG_MTD_PARTITIONS ++static const char *fsl_nfc_pprobes[] = { "cmdlinepart", NULL }; ++#endif ++#if 0 ++static struct nand_ecclayout nand_hw_eccoob_512 = { ++	.eccbytes = 8, ++	.eccpos = { ++		8, 9, 10, 11, 12, 13, 14, 15, ++	}, ++	.oobfree = { ++		{0, 5} /* byte 5 is factory bad block marker */ ++	}, ++}; ++#endif ++ ++static struct nand_ecclayout fsl_nfc_ecc45 = { ++	.eccbytes = 45, ++	.eccpos = {19, 20, 21, 22, 23, ++		   24, 25, 26, 27, 28, 29, 30, 31, ++		   32, 33, 34, 35, 36, 37, 38, 39, ++		   40, 41, 42, 43, 44, 45, 46, 47, ++		   48, 49, 50, 51, 52, 53, 54, 55, ++		   56, 57, 58, 59, 60, 61, 62, 63}, ++	.oobfree = { ++		{.offset = 8, ++		 .length = 11} } ++}; ++ ++ ++#if 0 ++static struct nand_ecclayout nand_hw_eccoob_2k = { ++	.eccbytes = 32, ++	.eccpos = { ++		/* 8 bytes of ecc for each 512 bytes of data */ ++		8, 9, 10, 11, 12, 13, 14, 15, ++		24, 25, 26, 27, 28, 29, 30, 31, ++		40, 41, 42, 43, 44, 45, 46, 47, ++		56, 57, 58, 59, 60, 61, 62, 63, ++	}, ++	.oobfree = { ++		{2, 5}, /* bytes 0 and 1 are factory bad block markers */ ++		{16, 7}, ++		{32, 7}, ++		{48, 7}, ++	}, ++}; ++ ++ ++/* ecc struct for nand 5125 */ ++static struct nand_ecclayout nand5125_hw_eccoob_2k = { ++	.eccbytes = 60, ++	.eccpos = { ++		/* 60 bytes of ecc for one page bytes of data */ ++		4, 5, ++		6, 7, 8, 9, 10, 11, 12, 13, 14, 15, ++		16, 17, 18, 19, 20, 21, 22, 23, 24, 25, ++		26, 27, 28, 29, 30, 31, 32, 33, 34, 35, ++		36, 37, 38, 39, 40, 41, 42, 43, 44, 45, ++		46, 47, 48, 49, 50, 51, 52, 53, 54, 55, ++		56, 57, 58, 59, 60, 61, 62, 63, ++	}, ++	.oobfree = { ++		{2, 2}, /* bytes 0 and 1 are factory bad block markers */ ++	}, ++}; ++#endif ++ ++static inline u32 nfc_read(struct mtd_info *mtd, uint reg) ++{ ++	struct nand_chip *chip = mtd->priv; ++	struct fsl_nfc_prv *prv = chip->priv; ++ ++	return in_be32(prv->regs + reg); ++} ++ ++/* Write NFC register */ ++static inline void nfc_write(struct mtd_info *mtd, uint reg, u32 val) ++{ ++	struct nand_chip *chip = mtd->priv; ++	struct fsl_nfc_prv *prv = chip->priv; ++ ++	out_be32(prv->regs + reg, val); ++} ++ ++/* Set bits in NFC register */ ++static inline void nfc_set(struct mtd_info *mtd, uint reg, u32 bits) ++{ ++	nfc_write(mtd, reg, nfc_read(mtd, reg) | bits); ++} ++ ++/* Clear bits in NFC register */ ++static inline void nfc_clear(struct mtd_info *mtd, uint reg, u32 bits) ++{ ++	nfc_write(mtd, reg, nfc_read(mtd, reg) & ~bits); ++} ++ ++static inline void ++nfc_set_field(struct mtd_info *mtd, u32 reg, u32 mask, u32 shift, u32 val) ++{ ++	struct nand_chip *chip = mtd->priv; ++	struct fsl_nfc_prv *prv = chip->priv; ++ ++	out_be32(prv->regs + reg, ++			(in_be32(prv->regs + reg) & (~mask)) ++			| val << shift); ++} ++ ++static inline int ++nfc_get_field(struct mtd_info *mtd, u32 reg, u32 field_mask) ++{ ++	struct nand_chip *chip = mtd->priv; ++	struct fsl_nfc_prv *prv = chip->priv; ++ ++	return in_be32(prv->regs + reg) & field_mask; ++} ++ ++static inline u8 nfc_check_status(struct mtd_info *mtd) ++{ ++	u8 fls_status = 0; ++	fls_status = nfc_get_field(mtd, NFC_FLASH_STATUS2, STATUS_BYTE1_MASK); ++	return fls_status; ++} ++ ++/* clear cmd_done and cmd_idle falg for the coming command */ ++static void fsl_nfc_clear(struct mtd_info *mtd) ++{ ++	nfc_write(mtd, NFC_IRQ_STATUS, 1 << CMD_DONE_CLEAR_SHIFT); ++	nfc_write(mtd, NFC_IRQ_STATUS, 1 << IDLE_CLEAR_SHIFT); ++} ++ ++/* Wait for operation complete */ ++static void fsl_nfc_done(struct mtd_info *mtd) ++{ ++	struct nand_chip *chip = mtd->priv; ++	struct fsl_nfc_prv *prv = chip->priv; ++	int rv; ++ ++	nfc_set(mtd, NFC_IRQ_STATUS, IDLE_EN_MASK); ++ ++	nfc_set_field(mtd, NFC_FLASH_CMD2, START_MASK, ++			START_SHIFT, 1); ++ ++	if (!nfc_get_field(mtd, NFC_IRQ_STATUS, IDLE_IRQ_MASK)) { ++		rv = wait_event_timeout(prv->irq_waitq, ++			nfc_get_field(mtd, NFC_IRQ_STATUS, ++				IDLE_IRQ_MASK), NFC_TIMEOUT); ++		if (!rv) ++			printk(KERN_DEBUG DRV_NAME ++				": Timeout while waiting for BUSY.\n"); ++	} ++	fsl_nfc_clear(mtd); ++} ++ ++static inline u8 fsl_nfc_get_id(struct mtd_info *mtd, int col) ++{ ++	u32 flash_id1 = 0; ++	u8 *pid; ++ ++	flash_id1 = nfc_read(mtd, NFC_FLASH_STATUS1); ++	pid = (u8 *)&flash_id1; ++ ++	return *(pid + col); ++} ++ ++static inline u8 fsl_nfc_get_status(struct mtd_info *mtd) ++{ ++	u32 flash_status = 0; ++	u8 *pstatus; ++ ++	flash_status = nfc_read(mtd, NFC_FLASH_STATUS2); ++	pstatus = (u8 *)&flash_status; ++ ++	return *(pstatus + 3); ++} ++ ++/* Invoke command cycle */ ++static inline void ++fsl_nfc_send_cmd(struct mtd_info *mtd, u32 cmd_byte1, ++		u32 cmd_byte2, u32 cmd_code) ++{ ++	fsl_nfc_clear(mtd); ++	nfc_set_field(mtd, NFC_FLASH_CMD2, CMD_BYTE1_MASK, ++			CMD_BYTE1_SHIFT, cmd_byte1); ++ ++	nfc_set_field(mtd, NFC_FLASH_CMD1, CMD_BYTE2_MASK, ++			CMD_BYTE2_SHIFT, cmd_byte2); ++ ++	nfc_set_field(mtd, NFC_FLASH_CMD2, BUFNO_MASK, ++			BUFNO_SHIFT, 0); ++ ++	nfc_set_field(mtd, NFC_FLASH_CMD2, CMD_CODE_MASK, ++			CMD_CODE_SHIFT, cmd_code); ++ ++	if (cmd_code == RANDOM_OUT_CMD_CODE) ++		nfc_set_field(mtd, NFC_FLASH_CMD2, BUFNO_MASK, ++			BUFNO_SHIFT, 1); ++} ++ ++/* Receive ID and status from NAND flash */ ++static inline void ++fsl_nfc_send_one_byte(struct mtd_info *mtd, u32 cmd_byte1, u32 cmd_code) ++{ ++	fsl_nfc_clear(mtd); ++ ++	nfc_set_field(mtd, NFC_FLASH_CMD2, CMD_BYTE1_MASK, ++			CMD_BYTE1_SHIFT, cmd_byte1); ++ ++	nfc_set_field(mtd, NFC_FLASH_CMD2, BUFNO_MASK, ++			BUFNO_SHIFT, 0); ++ ++	nfc_set_field(mtd, NFC_FLASH_CMD2, CMD_CODE_MASK, ++			CMD_CODE_SHIFT, cmd_code); ++} ++ ++/* NFC interrupt handler */ ++static irqreturn_t ++fsl_nfc_irq(int irq, void *data) ++{ ++	struct mtd_info *mtd = data; ++	struct nand_chip *chip = mtd->priv; ++	struct fsl_nfc_prv *prv = chip->priv; ++ ++	nfc_clear(mtd, NFC_IRQ_STATUS, IDLE_EN_MASK); ++	wake_up(&prv->irq_waitq); ++ ++	return IRQ_HANDLED; ++} ++ ++/* Do address cycle(s) */ ++static void ++fsl_nfc_addr_cycle(struct mtd_info *mtd, int column, int page) ++{ ++ ++	if (column != -1) { ++		nfc_set_field(mtd, NFC_COL_ADDR, ++				COL_ADDR_MASK, ++				COL_ADDR_SHIFT, column); ++	} ++ ++	if (page != -1) { ++		nfc_set_field(mtd, NFC_ROW_ADDR, ++				ROW_ADDR_MASK, ++				ROW_ADDR_SHIFT, page); ++	} ++ ++	/* DMA Disable */ ++	nfc_clear(mtd, NFC_FLASH_CONFIG, CONFIG_DMA_REQ_MASK); ++ ++	/* PAGE_CNT = 1 */ ++	nfc_set_field(mtd, NFC_FLASH_CONFIG, CONFIG_PAGE_CNT_MASK, ++			CONFIG_PAGE_CNT_SHIFT, 0x1); ++} ++ ++/* Control chips select signal on m54418twr board */ ++static void ++m54418twr_select_chip(struct mtd_info *mtd, int chip) ++{ ++	if (chip < 0) { ++		MCF_GPIO_PAR_FBCTL &= (MCF_GPIO_PAR_FBCTL_ALE_MASK & ++				   MCF_GPIO_PAR_FBCTL_TA_MASK); ++		MCF_GPIO_PAR_FBCTL |= MCF_GPIO_PAR_FBCTL_ALE_FB_TS | ++				   MCF_GPIO_PAR_FBCTL_TA_TA; ++ ++		MCF_GPIO_PAR_BE = ++		    MCF_GPIO_PAR_BE_BE3_BE3 | MCF_GPIO_PAR_BE_BE2_BE2 | ++		    MCF_GPIO_PAR_BE_BE1_BE1 | MCF_GPIO_PAR_BE_BE0_BE0; ++ ++		MCF_GPIO_PAR_CS &= ~MCF_GPIO_PAR_CS_CS1_NFC_CE; ++		MCF_GPIO_PAR_CS |= MCF_GPIO_PAR_CS_CS0_CS0; ++		return; ++	} ++ ++	MCF_GPIO_PAR_FBCTL &= (MCF_GPIO_PAR_FBCTL_ALE_MASK & ++			MCF_GPIO_PAR_FBCTL_TA_MASK); ++	MCF_GPIO_PAR_FBCTL |= MCF_GPIO_PAR_FBCTL_ALE_FB_ALE | ++			MCF_GPIO_PAR_FBCTL_TA_NFC_RB; ++	MCF_GPIO_PAR_BE = MCF_GPIO_PAR_BE_BE3_FB_A1 | ++		MCF_GPIO_PAR_BE_BE2_FB_A0 | ++		MCF_GPIO_PAR_BE_BE1_BE1 | MCF_GPIO_PAR_BE_BE0_BE0; ++ ++	MCF_GPIO_PAR_CS &= (MCF_GPIO_PAR_BE_BE3_MASK & ++		MCF_GPIO_PAR_BE_BE2_MASK); ++	MCF_GPIO_PAR_CS |= MCF_GPIO_PAR_CS_CS1_NFC_CE; ++	return; ++} ++ ++/* Read NAND Ready/Busy signal */ ++static int ++fsl_nfc_dev_ready(struct mtd_info *mtd) ++{ ++	/* ++	 * NFC handles ready/busy signal internally. Therefore, this function ++	 * always returns status as ready. ++	 */ ++	return 1; ++} ++ ++/* Write command to NAND flash */ ++static void ++fsl_nfc_command(struct mtd_info *mtd, unsigned command, ++					int column, int page) ++{ ++	struct nand_chip *chip = mtd->priv; ++	struct fsl_nfc_prv *prv = chip->priv; ++ ++	prv->column = (column >= 0) ? column : 0; ++	prv->spareonly = 0; ++	get_id = 0; ++	get_status = 0; ++ ++	if (page != -1) ++		prv->page = page; ++ ++	nfc_set_field(mtd, NFC_FLASH_CONFIG, ++		CONFIG_ECC_MODE_MASK, ++		CONFIG_ECC_MODE_SHIFT, ECC_45_BYTE); ++ ++	if (!(page%0x40)) { ++			nfc_set_field(mtd, NFC_FLASH_CONFIG, ++				CONFIG_ECC_MODE_MASK, ++				CONFIG_ECC_MODE_SHIFT, ECC_BYPASS); ++	} ++ ++	switch (command) { ++	case NAND_CMD_PAGEPROG: ++		if (!(prv->page%0x40)) ++			nfc_set_field(mtd, NFC_FLASH_CONFIG, ++				CONFIG_ECC_MODE_MASK, ++				CONFIG_ECC_MODE_SHIFT, ECC_BYPASS); ++ ++		fsl_nfc_send_cmd(mtd, ++				PROGRAM_PAGE_CMD_BYTE1, ++				PROGRAM_PAGE_CMD_BYTE2, ++				PROGRAM_PAGE_CMD_CODE); ++		break; ++	/* ++	 * NFC does not support sub-page reads and writes, ++	 * so emulate them using full page transfers. ++	 */ ++	case NAND_CMD_READ0: ++		column = 0; ++		goto read0; ++		break; ++ ++	case NAND_CMD_READ1: ++		prv->column += 256; ++		command = NAND_CMD_READ0; ++		column = 0; ++		goto read0; ++		break; ++ ++	case NAND_CMD_READOOB: ++		prv->spareonly = 1; ++		command = NAND_CMD_READ0; ++		column = 0; ++read0: ++		fsl_nfc_send_cmd(mtd, ++				PAGE_READ_CMD_BYTE1, ++				PAGE_READ_CMD_BYTE2, ++				READ_PAGE_CMD_CODE); ++		break; ++ ++	case NAND_CMD_SEQIN: ++		fsl_nfc_command(mtd, NAND_CMD_READ0, column, page); ++		column = 0; ++		break; ++ ++	case NAND_CMD_ERASE1: ++		fsl_nfc_send_cmd(mtd, ++				ERASE_CMD_BYTE1, ++				ERASE_CMD_BYTE2, ++				ERASE_CMD_CODE); ++		break; ++	case NAND_CMD_ERASE2: ++		return; ++	case NAND_CMD_READID: ++		get_id = 1; ++		fsl_nfc_send_one_byte(mtd, command, READ_ID_CMD_CODE); ++		break; ++	case NAND_CMD_STATUS: ++		get_status = 1; ++		fsl_nfc_send_one_byte(mtd, command, STATUS_READ_CMD_CODE); ++		break; ++	case NAND_CMD_RNDOUT: ++		fsl_nfc_send_cmd(mtd, ++				RANDOM_OUT_CMD_BYTE1, ++				RANDOM_OUT_CMD_BYTE2, ++				RANDOM_OUT_CMD_CODE); ++		break; ++	case NAND_CMD_RESET: ++		fsl_nfc_send_one_byte(mtd, command, RESET_CMD_CODE); ++		break; ++	default: ++		return; ++	} ++ ++	fsl_nfc_addr_cycle(mtd, column, page); ++ ++	fsl_nfc_done(mtd); ++} ++ ++/* Copy data from/to NFC spare buffers. */ ++static void ++fsl_nfc_copy_spare(struct mtd_info *mtd, uint offset, ++			u8 *buffer, uint size, int wr) ++{ ++	struct nand_chip *nand = mtd->priv; ++	struct fsl_nfc_prv *prv = nand->priv; ++	uint o, s, sbsize, blksize; ++ ++	/* ++	 * NAND spare area is available through NFC spare buffers. ++	 * The NFC divides spare area into (page_size / 512) chunks. ++	 * Each chunk is placed into separate spare memory area, using ++	 * first (spare_size / num_of_chunks) bytes of the buffer. ++	 * ++	 * For NAND device in which the spare area is not divided fully ++	 * by the number of chunks, number of used bytes in each spare ++	 * buffer is rounded down to the nearest even number of bytes, ++	 * and all remaining bytes are added to the last used spare area. ++	 * ++	 * For more information read section 26.6.10 of MPC5121e ++	 * Microcontroller Reference Manual, Rev. 3. ++	 */ ++ ++	/* Calculate number of valid bytes in each spare buffer */ ++/*	sbsize = (mtd->oobsize / (mtd->writesize / 512)) & ~1;*/ ++	sbsize = (mtd->oobsize / (mtd->writesize / 2048)) & ~1; ++ ++ ++	while (size) { ++		/* Calculate spare buffer number */ ++		s = offset / sbsize; ++		if (s > NFC_SPARE_BUFFERS - 1) ++			s = NFC_SPARE_BUFFERS - 1; ++ ++		/* ++		 * Calculate offset to requested data block in selected spare ++		 * buffer and its size. ++		 */ ++		o = offset - (s * sbsize); ++		blksize = min(sbsize - o, size); ++ ++		if (wr) ++			memcpy_toio(prv->regs + NFC_SPARE_AREA(s) + o, ++							buffer, blksize); ++		else { ++			memcpy_fromio(buffer, ++				prv->regs + NFC_SPARE_AREA(s) + o, blksize); ++		} ++ ++		buffer += blksize; ++		offset += blksize; ++		size -= blksize; ++	}; ++} ++ ++/* Copy data from/to NFC main and spare buffers */ ++static void ++fsl_nfc_buf_copy(struct mtd_info *mtd, u_char *buf, int len, int wr) ++{ ++	struct nand_chip *chip = mtd->priv; ++	struct fsl_nfc_prv *prv = chip->priv; ++	uint c = prv->column; ++	uint l; ++ ++	/* Handle spare area access */ ++	if (prv->spareonly || c >= mtd->writesize) { ++		/* Calculate offset from beginning of spare area */ ++		if (c >= mtd->writesize) ++			c -= mtd->writesize; ++ ++		prv->column += len; ++		fsl_nfc_copy_spare(mtd, c, buf, len, wr); ++		return; ++	} ++ ++	/* ++	 * Handle main area access - limit copy length to prevent ++	 * crossing main/spare boundary. ++	 */ ++	l = min((uint)len, mtd->writesize - c); ++	prv->column += l; ++ ++	if (wr) ++		memcpy_toio(prv->regs + NFC_MAIN_AREA(0) + c, buf, l); ++	else { ++		if (get_status) { ++			get_status = 0; ++			*buf = fsl_nfc_get_status(mtd); ++		} else if (l == 1 && c <= 3 && get_id) { ++			*buf = fsl_nfc_get_id(mtd, c); ++		} else ++			memcpy_fromio(buf, prv->regs + NFC_MAIN_AREA(0) + c, l); ++	} ++ ++	/* Handle crossing main/spare boundary */ ++	if (l != len) { ++		buf += l; ++		len -= l; ++		fsl_nfc_buf_copy(mtd, buf, len, wr); ++	} ++} ++ ++/* Read data from NFC buffers */ ++static void ++fsl_nfc_read_buf(struct mtd_info *mtd, u_char *buf, int len) ++{ ++	fsl_nfc_buf_copy(mtd, buf, len, 0); ++} ++ ++/* Write data to NFC buffers */ ++static void ++fsl_nfc_write_buf(struct mtd_info *mtd, const u_char *buf, int len) ++{ ++	fsl_nfc_buf_copy(mtd, (u_char *)buf, len, 1); ++} ++ ++/* Compare buffer with NAND flash */ ++static int ++fsl_nfc_verify_buf(struct mtd_info *mtd, const u_char *buf, int len) ++{ ++	u_char tmp[256]; ++	uint bsize; ++ ++	while (len) { ++		bsize = min(len, 256); ++		fsl_nfc_read_buf(mtd, tmp, bsize); ++ ++		if (memcmp(buf, tmp, bsize)) ++			return 1; ++ ++		buf += bsize; ++		len -= bsize; ++	} ++ ++	return 0; ++} ++ ++/* Read byte from NFC buffers */ ++static u8 ++fsl_nfc_read_byte(struct mtd_info *mtd) ++{ ++	u8 tmp; ++	fsl_nfc_read_buf(mtd, &tmp, sizeof(tmp)); ++	return tmp; ++} ++ ++/* Read word from NFC buffers */ ++static u16 ++fsl_nfc_read_word(struct mtd_info *mtd) ++{ ++	u16 tmp; ++	fsl_nfc_read_buf(mtd, (u_char *)&tmp, sizeof(tmp)); ++	return tmp; ++} ++ ++#if 0 ++static void fsl_nfc_check_ecc_status(struct mtd_info *mtd) ++{ ++	struct nand_chip *chip = mtd->priv; ++	struct fsl_nfc_prv *prv = chip->priv; ++	u8 ecc_status, ecc_count; ++ ++	ecc_status = *(u8 *)(prv->regs + ECC_SRAM_ADDR * 8 + 7); ++	ecc_count = ecc_status & ECC_ERR_COUNT; ++	if (ecc_status & ECC_STATUS_MASK) { ++		/*mtd->ecc_stats.failed++;*/ ++		printk("ECC failed to correct all errors!\n"); ++	} else if (ecc_count) { ++		/*mtd->ecc_stats.corrected += ecc_count;*/ ++		printk(KERN_INFO"ECC corrected %d errors\n", ecc_count); ++	} ++ ++} ++#endif ++ ++static void ++copy_from_to_spare(struct mtd_info *mtd, void *pbuf, int len, int wr) ++{ ++	struct nand_chip *chip = mtd->priv; ++	struct fsl_nfc_prv *prv = chip->priv; ++	int i, copy_count, copy_size; ++ ++/*	copy_count = mtd->writesize / 512;*/ ++	copy_count = mtd->writesize / 2048; ++	/* ++	 * Each spare area has 16 bytes for 512, 2K and normal 4K nand. ++	 * For 4K nand with large 218 byte spare size, the size is 26 bytes for ++	 * the first 7 buffers and 36 for the last. ++	 */ ++/*	copy_size = mtd->oobsize == 218 ? 26 : 16;*/ ++	copy_size = 64; ++ ++	/* ++	 * Each spare area has 16 bytes for 512, 2K and normal 4K nand. ++	 * For 4K nand with large 218 byte spare size, the size is 26 ++	 * bytes for the first 7 buffers and 36 for the last. ++	 */ ++	for (i = 0; i < copy_count - 1 && len > 0; i++) { ++		if (wr) ++			memcpy_toio(prv->regs + NFC_SPARE_AREA(i), ++					pbuf, MIN(len, copy_size)); ++		else ++			memcpy_fromio(pbuf, prv->regs + NFC_SPARE_AREA(i), ++					MIN(len, copy_size)); ++		pbuf += copy_size; ++		len -= copy_size; ++	} ++	if (len > 0) { ++		if (wr) ++			memcpy_toio(prv->regs + NFC_SPARE_AREA(i), ++				pbuf, len); ++		else ++			memcpy_fromio(pbuf, ++				prv->regs + NFC_SPARE_AREA(i), len); ++	} ++} ++ ++ ++static int fsl_nfc_read_oob(struct mtd_info *mtd, struct nand_chip *chip, ++				int page, int sndcmd) ++{ ++	fsl_nfc_command(mtd, NAND_CMD_READ0, 0, page); ++ ++	copy_from_to_spare(mtd, chip->oob_poi, mtd->oobsize, 0); ++	return 0; ++} ++ ++static int fsl_nfc_write_oob(struct mtd_info *mtd, struct nand_chip *chip, ++					int page) ++{ ++	fsl_nfc_command(mtd, NAND_CMD_READ0, 0, page); ++	/* copy the oob data */ ++	copy_from_to_spare(mtd, chip->oob_poi, mtd->oobsize, 1); ++	fsl_nfc_command(mtd, NAND_CMD_PAGEPROG, 0, page); ++	return 0; ++} ++ ++static int fsl_nfc_read_page(struct mtd_info *mtd, struct nand_chip *chip, ++					uint8_t *buf, int page) ++{ ++	struct fsl_nfc_prv *prv = chip->priv; ++	/*fsl_nfc_check_ecc_status(mtd);*/ ++ ++	memcpy_fromio((void *)buf, prv->regs + NFC_MAIN_AREA(0), ++			mtd->writesize); ++	copy_from_to_spare(mtd, chip->oob_poi, mtd->oobsize, 0); ++	return 0; ++} ++ ++static void fsl_nfc_write_page(struct mtd_info *mtd, ++		struct nand_chip *chip, const uint8_t *buf) ++{ ++	struct fsl_nfc_prv *prv = chip->priv; ++	memcpy_toio(prv->regs + NFC_MAIN_AREA(0), buf, mtd->writesize); ++	copy_from_to_spare(mtd, chip->oob_poi, mtd->oobsize, 1); ++} ++ ++static void fsl_nfc_enable_hwecc(struct mtd_info *mtd, int mode) ++{ ++	return; ++} ++ ++/* Free driver resources */ ++static void ++fsl_nfc_free(struct  platform_device *dev, struct mtd_info *mtd) ++{ ++	struct nand_chip *chip = mtd->priv; ++	struct fsl_nfc_prv *prv = chip->priv; ++ ++	kfree(prv); ++} ++ ++static int __devinit ++fsl_nfc_probe(struct platform_device *pdev) ++{ ++	struct fsl_nfc_prv *prv; ++	struct resource *res; ++	struct mtd_info *mtd; ++#ifdef CONFIG_MTD_PARTITIONS ++	struct mtd_partition *parts; ++#endif ++	struct nand_chip *chip; ++	unsigned long regs_paddr, regs_size; ++	int retval = 0; ++ ++	prv = kzalloc(sizeof(*prv), GFP_KERNEL); ++	if (!prv) { ++		printk(KERN_ERR DRV_NAME ": Memory exhausted!\n"); ++		return -ENOMEM; ++	} ++	mtd = &prv->mtd; ++	chip = &prv->chip; ++ ++	mtd->priv = chip; ++	chip->priv = prv; ++ ++	prv->irq = platform_get_irq(pdev, 0); ++	if (prv->irq <= 0) { ++		printk(KERN_ERR DRV_NAME ": Error mapping IRQ!\n"); ++		return -EINVAL; ++	} ++ ++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++	if (res == NULL) { ++		printk(KERN_ERR "%s platform_get_resource MEM  failed %x\n", ++			__func__, (unsigned int)res); ++		retval = -ENOMEM; ++		goto error; ++	} ++	regs_paddr = res->start; ++	regs_size = res->end - res->start + 1; ++ ++#if 0 ++	if (!request_mem_region(regs_paddr, regs_size, DRV_NAME)) { ++		printk(KERN_ERR DRV_NAME ": Error requesting memory region!\n"); ++		return -EBUSY; ++	} ++ ++	prv->regs = ioremap(regs_paddr, regs_size); ++#endif ++	prv->regs = (void __iomem *)regs_paddr; ++	if (!prv->regs) { ++		printk(KERN_ERR DRV_NAME ": Error mapping memory region!\n"); ++		return -ENOMEM; ++	} ++ ++	mtd->name = "NAND"; ++	mtd->writesize = 2048; ++	mtd->oobsize = 64; ++ ++	chip->dev_ready = fsl_nfc_dev_ready; ++	chip->cmdfunc = fsl_nfc_command; ++	chip->read_byte = fsl_nfc_read_byte; ++	chip->read_word = fsl_nfc_read_word; ++	chip->read_buf = fsl_nfc_read_buf; ++	chip->write_buf = fsl_nfc_write_buf; ++	chip->verify_buf = fsl_nfc_verify_buf; ++	chip->options = NAND_NO_AUTOINCR | NAND_USE_FLASH_BBT | ++				NAND_BUSWIDTH_16 | NAND_CACHEPRG; ++ ++	chip->select_chip = m54418twr_select_chip; ++ ++	if (hardware_ecc) { ++		chip->ecc.read_page = fsl_nfc_read_page; ++		chip->ecc.write_page = fsl_nfc_write_page; ++		chip->ecc.read_oob = fsl_nfc_read_oob; ++		chip->ecc.write_oob = fsl_nfc_write_oob; ++		chip->ecc.layout = &fsl_nfc_ecc45; ++ ++		/* propagate ecc.layout to mtd_info */ ++		mtd->ecclayout = chip->ecc.layout; ++		chip->ecc.calculate = NULL; ++		chip->ecc.hwctl = fsl_nfc_enable_hwecc; ++		chip->ecc.correct = NULL; ++		chip->ecc.mode = NAND_ECC_HW; ++		/* RS-ECC is applied for both MAIN+SPARE not MAIN alone */ ++		chip->ecc.steps = 1; ++		chip->ecc.bytes = 45; ++		chip->ecc.size = 0x800; ++ ++		/* set ECC mode = ECC_45_BYTE */ ++		nfc_set_field(mtd, NFC_FLASH_CONFIG, ++				CONFIG_ECC_MODE_MASK, ++				CONFIG_ECC_MODE_SHIFT, ECC_45_BYTE); ++		/* set ECC_STATUS write position */ ++		nfc_set_field(mtd, NFC_FLASH_CONFIG, ++				CONFIG_ECC_SRAM_ADDR_MASK, ++				CONFIG_ECC_SRAM_ADDR_SHIFT, ECC_SRAM_ADDR); ++		/* enable ECC_STATUS results write */ ++		nfc_set_field(mtd, NFC_FLASH_CONFIG, ++				CONFIG_ECC_SRAM_REQ_MASK, ++				CONFIG_ECC_SRAM_REQ_SHIFT, 1); ++	} else { ++		chip->ecc.mode = NAND_ECC_SOFT; ++		/* set ECC BY_PASS */ ++		nfc_set_field(mtd, NFC_FLASH_CONFIG, ++				CONFIG_ECC_MODE_MASK, ++				CONFIG_ECC_MODE_SHIFT, ECC_BYPASS); ++	} ++	chip->bbt_td = &bbt_main_descr; ++	chip->bbt_md = &bbt_mirror_descr; ++	bbt_main_descr.pattern = bbt_pattern; ++	bbt_mirror_descr.pattern = mirror_pattern; ++ ++	init_waitqueue_head(&prv->irq_waitq); ++	retval = request_irq(prv->irq, fsl_nfc_irq, IRQF_DISABLED, ++			DRV_NAME, mtd); ++	if (retval) { ++		printk(KERN_ERR DRV_NAME ": Error requesting IRQ!\n"); ++		goto error; ++	} ++ ++	/* SET SECTOR SIZE */ ++	nfc_write(mtd, NFC_SECTOR_SIZE, PAGE_2K | PAGE_64); ++ ++	nfc_set_field(mtd, NFC_FLASH_CONFIG, ++			CONFIG_ADDR_AUTO_INCR_MASK, ++			CONFIG_ADDR_AUTO_INCR_SHIFT, 0); ++ ++	nfc_set_field(mtd, NFC_FLASH_CONFIG, ++			CONFIG_BUFNO_AUTO_INCR_MASK, ++			CONFIG_BUFNO_AUTO_INCR_SHIFT, 0); ++	/* SET FAST_FLASH = 1 */ ++#if 0 ++	nfc_set_field(mtd, NFC_FLASH_CONFIG, ++			CONFIG_FAST_FLASH_MASK, ++			CONFIG_FAST_FLASH_SHIFT, 1); ++#endif ++ ++	nfc_set_field(mtd, NFC_FLASH_CONFIG, ++			CONFIG_16BIT_MASK, ++			CONFIG_16BIT_SHIFT, 1); ++ ++ ++	/* Detect NAND chips */ ++	if (nand_scan(mtd, 1)) { ++		printk(KERN_ERR DRV_NAME ": NAND Flash not found !\n"); ++		free_irq(prv->irq, mtd); ++		retval = -ENXIO; ++		goto error; ++	} ++ ++	platform_set_drvdata(pdev, mtd); ++ ++	/* Register device in MTD */ ++#ifdef CONFIG_MTD_PARTITIONS ++	retval = parse_mtd_partitions(mtd, fsl_nfc_pprobes, &parts, 0); ++	if (retval < 0) { ++		printk(KERN_ERR DRV_NAME ": Error parsing MTD partitions!\n"); ++		free_irq(prv->irq, mtd); ++		retval = -EINVAL; ++		goto error; ++	} ++ ++	printk(KERN_DEBUG "parse partition: partnr = %d\n", retval); ++ ++	if (retval > 0) ++		retval = add_mtd_partitions(mtd, parts, retval); ++	else ++#endif ++		retval = add_mtd_device(mtd); ++ ++	if (retval) { ++		printk(KERN_ERR DRV_NAME ": Error adding MTD device!\n"); ++		free_irq(prv->irq, mtd); ++		goto error; ++	} ++ ++	return 0; ++error: ++	fsl_nfc_free(pdev, mtd); ++	return retval; ++} ++ ++static int __exit ++fsl_nfc_remove(struct platform_device *pdev) ++{ ++	struct mtd_info *mtd = platform_get_drvdata(pdev); ++	struct nand_chip *chip = mtd->priv; ++	struct fsl_nfc_prv *prv = chip->priv; ++ ++	nand_release(mtd); ++	free_irq(prv->irq, mtd); ++	fsl_nfc_free(pdev, mtd); ++ ++	return 0; ++} ++ ++static struct platform_driver fsl_nfc_driver = { ++	.probe		= fsl_nfc_probe, ++	.remove		= __exit_p(fsl_nfc_remove), ++	.suspend	= NULL, ++	.resume		= NULL, ++	.driver		= { ++		.name	= DRV_NAME, ++		.owner	= THIS_MODULE, ++	}, ++}; ++ ++static int __init fsl_nfc_init(void) ++{ ++	pr_info("FSL NFC MTD nand Driver %s\n", DRV_VERSION); ++	if (platform_driver_register(&fsl_nfc_driver) != 0) { ++		printk(KERN_ERR DRV_NAME ": Driver register failed!\n"); ++		return -ENODEV; ++	} ++	return 0; ++} ++ ++static void __exit fsl_nfc_cleanup(void) ++{ ++	platform_driver_unregister(&fsl_nfc_driver); ++} ++ ++module_init(fsl_nfc_init); ++module_exit(fsl_nfc_cleanup); ++ ++MODULE_AUTHOR("Freescale Semiconductor, Inc."); ++MODULE_DESCRIPTION("FSL NFC NAND MTD driver"); ++MODULE_LICENSE("GPL"); ++MODULE_VERSION(DRV_VERSION);  | 
