?? mx2_nand.c
字號:
/****************************************************************************** drivers/mtd/nand/mx2_nand.c driver for i.MX21 on-chip NAND Flash controller. tested with NAND Flash devices that come with MX21ADS board: SAMSUNG K9F1208Q0A (8bit i/o) SAMSUNG K9F5616Q0C (16Bit i/o) Copyright (c) 2004 MontaVista Software, Inc. <source@mvista.com> Based on mx2 nand support code from Motorola's MX21 BSP: Copyright (C) 2003 Motorola Inc. Ltd This program 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. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ********************************************************************************/#include <linux/slab.h>#include <linux/init.h>#include <linux/module.h>#include <linux/delay.h>#include <linux/errno.h>#include <linux/sched.h>#include <linux/types.h>#include <linux/mtd/mtd.h>#include <linux/mtd/nand.h>#include <linux/mtd/partitions.h>#include <linux/interrupt.h>#include <linux/ioport.h>#include <asm/arch/gpio.h>#include <asm/arch/pll.h>#include <asm/arch/hardware.h>static void mx2nand_setup_clock(void);#if 1 /*CEE LDM*/static char mx2nand_ldm_inited;#include <linux/device.h>extern void mx21_ldm_bus_register(struct device *device, struct device_driver *driver);extern void mx21_ldm_bus_unregister(struct device *device, struct device_driver *driver);static int mx2nand_freq_scale(struct bus_op_point * op, u32 level){ mx2nand_setup_clock(); return 0;}static struct device_driver __driver_ldm = { .name = "mx2_nand", .scale = mx2nand_freq_scale,};static struct device __device_ldm = { .name = "NAND FLASH", .bus_id = "mx2_nand", .driver = &__driver_ldm, .power_state = DPM_POWER_ON,};#endif#define NAND_FLASH_CONFIG2_INT 0x8000#define NAND_FLASH_CONFIG2_FCMD 0x1#define NAND_FLASH_CONFIG2_FADD 0x2#define NAND_FLASH_CONFIG2_FDI 0x4#define NAND_FLASH_CONFIG2_PAGE_OUT 0x8#define NAND_FLASH_CONFIG2_ID_OUT 0x10#define NAND_FLASH_CONFIG2_STATUS_OUT 0x20/*critical section*/#define MX2NAND_DECLARE_CS_FLAGS(name) u32 name#ifdef CONFIG_MX2_16_BIT_NAND#define MX2NAND_ENTER_CS(x) do { \ save_flags(x); \ cli(); \ SYS_FMCR |= (1 << 4); \} while (0)#define MX2NAND_EXIT_CS(x) do { \ SYS_FMCR &= ~(1 << 4); \ restore_flags(x); \} while (0)#else#define MX2NAND_ENTER_CS(x) do { \ save_flags(x); \ cli(); \} while (0)#define MX2NAND_EXIT_CS(x) do { \ restore_flags(x); \} while (0)#endif#ifdef CONFIG_MTD_CMDLINE_PARTSconst char *mx2nand_probes[] = { "cmdlinepart", NULL };#endifstatic struct mtd_info *mx2nand_mtd = NULL;static u8 mx2nand_region_init;static u8 mx2nand_gpio_init;static void __init mx2nand_cleanup(void);#define NAND_TIMEOUT HZ*5struct mx2nand_priv { u_char mode; u_char cmd; u32 offset; u32 max_offset;};static uint8_t mx2nand_bi_pattern[] = { 0 }; /*bad block indicator pattern - I saw only 0's */#ifdef CONFIG_MX2_16_BIT_NANDstatic struct nand_oobinfo mx2nand_oob = { .useecc = MTD_NANDECC_AUTOPLACE, .eccbytes = 0, /* 0 instead of 3 to prevent writing attempts to ECC area */ .eccpos = {6, 7, 8}, /*no practical value - SW ECC write is disabled, handled by HW */ .oobfree = {{0, 6}, {12, 4}}, /*accessible bytes in the spare area */};static struct nand_bbt_descr mx2nand_bbt_descr = { .options = 0, .offs = 11, .len = 1, .pattern = mx2nand_bi_pattern,};#elsestatic struct nand_oobinfo mx2nand_oob = { .useecc = MTD_NANDECC_AUTOPLACE, .eccbytes = 0, /* 0 instead of 3 to prevent writing attempts to ECC area */ .eccpos = {6, 7, 8}, /*no practical value - SW ECC write is disabled, handled by HW */ .oobfree = {{0, 5}, {11, 5}}, /*accessible bytes in the spare area */};static struct nand_bbt_descr mx2nand_bbt_descr = { .options = 0, .offs = 5, .len = 1, .pattern = mx2nand_bi_pattern,};#endifstatic intmx2nand_scan_bbt(struct mtd_info *mtd){ nand_scan_bbt(mtd, &mx2nand_bbt_descr); return 0;}static intmx2nand_correct_data(struct mtd_info *mtd, u_char * dat, u_char * read_ecc, u_char * calc_ecc){/*ecc is handled entirely by the MX2 NFC*//*report ECC Uncorrectable error*/ if (NFC_ECC_STAT_RES & 0xA) return -1; else return 0;}static voidmx2nand_enable_hwecc(struct mtd_info *mtd, int mode){/*ecc is handled entirely by the MX2 NFC*/}static intmx2nand_calculate_ecc(struct mtd_info *mtd, const u_char * dat, u_char * ecc_code){/*ecc is handled entirely by the MX2 NFC*/ return 0;}static voidmx2nand_wait(void){ unsigned long timeout; timeout = jiffies + NAND_TIMEOUT; while (!(NFC_NF_CONFIG2 & NAND_FLASH_CONFIG2_INT)) { if (time_after(jiffies, timeout)) { printk(KERN_ERR "MX2_NAND: timeout waiting for Nand command complete\n"); return; } }}static voidmx2nand_request_data(int cmd){ MX2NAND_DECLARE_CS_FLAGS(flags); MX2NAND_ENTER_CS(flags); switch (cmd) { case NAND_CMD_READID: NFC_NF_CONFIG2 = NAND_FLASH_CONFIG2_ID_OUT; break; case NAND_CMD_STATUS: NFC_NF_CONFIG2 = NAND_FLASH_CONFIG2_STATUS_OUT; break; default: NFC_NF_CONFIG2 = NAND_FLASH_CONFIG2_PAGE_OUT; } mx2nand_wait(); MX2NAND_EXIT_CS(flags);}static u_charmx2nand_read_byte(struct mtd_info *mtd){ struct nand_chip *chip_priv = mtd->priv; struct mx2nand_priv *mx2_priv = chip_priv->priv; char b; u16 buf; u32 offset = mx2_priv->offset; int cmd = mx2_priv->cmd; if (offset == 0) { mx2nand_request_data(cmd); } if ((offset >= 512) || (cmd == NAND_CMD_READOOB)) buf = *((u16 *) NFC_SAB_BASE(3) + (offset >> 1)); else buf = *((u16 *) NFC_MAB_BASE(3) + (offset >> 1)); b = ((u8 *) & buf)[offset & 0x1];#ifdef CONFIG_MX2_16_BIT_NAND if (cmd == NAND_CMD_READID) offset++; /*skip 1 byte */#endif offset++; if (offset >= mx2_priv->max_offset) offset = 0; mx2_priv->offset = offset; return b;}static u16mx2nand_read_word(struct mtd_info *mtd){ u8 buf[2]; buf[0] = mx2nand_read_byte(mtd); buf[1] = mx2nand_read_byte(mtd); return *(u16 *) buf;}static voidmx2nand_send_command(struct mtd_info *mtd, u8 cmd){ struct nand_chip *chip_priv = mtd->priv; struct mx2nand_priv *mx2_priv = chip_priv->priv; MX2NAND_DECLARE_CS_FLAGS(flags); mx2_priv->cmd = cmd; /*remember command for further internal handling */ if (cmd == NAND_CMD_PAGEPROG) { MX2NAND_ENTER_CS(flags); NFC_NF_CONFIG2 = NAND_FLASH_CONFIG2_FDI; mx2nand_wait(); MX2NAND_EXIT_CS(flags); } /*send command */ NFC_NAND_FLASH_CMD = cmd; MX2NAND_ENTER_CS(flags); NFC_NF_CONFIG2 = NAND_FLASH_CONFIG2_FCMD; if (cmd != NAND_CMD_RESET) mx2nand_wait(); MX2NAND_EXIT_CS(flags); /*extra command processing for read/write-prepare commands */ switch (cmd) { case NAND_CMD_READ0: NFC_NF_CONFIG1 = 0x8 | 0x2; /*enable ECC, Spare + Main Area */ mx2_priv->offset = 0; mx2_priv->max_offset = 528; break; case NAND_CMD_READOOB: NFC_NF_CONFIG1 = 0xC | 0x2; /*enable ECC, Spare Area Only */ mx2_priv->offset = 0; mx2_priv->max_offset = 16; break; case NAND_CMD_READID: NFC_NF_CONFIG1 = 0x8 | 0x2; /*enable ECC, Spare + Main Area */ mx2_priv->offset = 0;#ifdef CONFIG_MX2_16_BIT_NAND mx2_priv->max_offset = 12;#else mx2_priv->max_offset = 6;#endif break; case NAND_CMD_STATUS: NFC_NF_CONFIG1 = 0x8 | 0x2; /*enable ECC, Spare + Main Area */ mx2_priv->offset = 0; mx2_priv->max_offset = 1; break; }}static voidmx2nand_send_address(u8 addr){ MX2NAND_DECLARE_CS_FLAGS(flags); NFC_NAND_FLASH_ADDR = addr; MX2NAND_ENTER_CS(flags); NFC_NF_CONFIG2 = NAND_FLASH_CONFIG2_FADD; mx2nand_wait(); MX2NAND_EXIT_CS(flags);}static voidmx2nand_write_byte(struct mtd_info *mtd, u_char byte){ struct nand_chip *chip_priv = mtd->priv; struct mx2nand_priv *mx2_priv = chip_priv->priv; u32 offset; u16 buf; int cmd; switch (mx2_priv->mode) { case NAND_CTL_SETCLE: mx2nand_send_command(mtd, byte); break; case NAND_CTL_SETALE: mx2nand_send_address(byte); break; default: offset = mx2_priv->offset; cmd = mx2_priv->cmd; if ((offset >= 512) || (cmd == NAND_CMD_READOOB)) buf = *((u16 *) NFC_SAB_BASE(3) + (offset >> 1)); else buf = *((u16 *) NFC_MAB_BASE(3) + (offset >> 1)); ((u8 *) & buf)[offset & 0x1] = byte; if ((offset >= 512) || (cmd == NAND_CMD_READOOB)) *((u16 *) NFC_SAB_BASE(3) + (offset >> 1)) = buf; else *((u16 *) NFC_MAB_BASE(3) + (offset >> 1)) = buf; offset++; if (offset >= mx2_priv->max_offset) offset = 0; mx2_priv->offset = offset;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -