📄 mp2520f.c
字号:
/* * NAND controller on MagicEye MP2520F * * Based on vivi/drivers/mtd/nand/mp2520f.c by bushi * * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive * for more details. */#include <config.h>#include <machine.h>#include <types.h>#include <mtd/mtd.h>#include <mtd/nand.h>#include <time.h>#include <vmalloc.h>#include <vstring.h>#include <errno.h>#define MP2520F_NAND_DEBUG 0#define USE_CPU_FCE 1#define USE_CPU_RnB 1#if MP2520F_NAND_DEBUG#define DPRINTK(x...) printk(x)#else#define DPRINTK(x...) (void)(0)#endif#define GPIO_nFCE0 GPIO_I0#define GPIO_nFCE1 GPIO_I1#define GPIO_nFCE2 GPIO_I2#define GPIO_nFCE3 GPIO_I3#define GPIO_RnB GPIO_J2extern int nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc);static struct mtd_info *mp2520f_nand_mtd = NULL;#if USE_CPU_FCE == 0static const int chipnr_to_gpiobit[16] = { 0xe,0xd,0xb,0x7,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf};#endifstatic void mp2520f_nand_select_chip(struct mtd_info *mtd, int chip){#if USE_CPU_FCE unsigned short memnandctrl = MEMNANDCTRL & 0xfffc; DPRINTK("%s(): chip = %d\n", __FUNCTION__, chip); if (chip >= 0 && chip < 4) { memnandctrl |= chip; } else { memnandctrl |= 1; // FIXME !! } MEMNANDCTRL = memnandctrl; DPRINTK("MEMNANDCTRL = 0x%04x\n", MEMNANDCTRL);#else# if 0 switch (chip) { case 0: write_gpio_bit(GPIO_nFCE0, 0); write_gpio_bit(GPIO_nFCE1, 1); write_gpio_bit(GPIO_nFCE2, 1); write_gpio_bit(GPIO_nFCE3, 1); break; case 1: write_gpio_bit(GPIO_nFCE0, 1); write_gpio_bit(GPIO_nFCE1, 0); write_gpio_bit(GPIO_nFCE2, 1); write_gpio_bit(GPIO_nFCE3, 1); break; case 2: write_gpio_bit(GPIO_nFCE0, 1); write_gpio_bit(GPIO_nFCE1, 1); write_gpio_bit(GPIO_nFCE2, 0); write_gpio_bit(GPIO_nFCE3, 1); break; case 3: write_gpio_bit(GPIO_nFCE0, 1); write_gpio_bit(GPIO_nFCE1, 1); write_gpio_bit(GPIO_nFCE2, 1); write_gpio_bit(GPIO_nFCE3, 0); break; default: write_gpio_bit(GPIO_nFCE0, 1); write_gpio_bit(GPIO_nFCE1, 1); write_gpio_bit(GPIO_nFCE2, 1); write_gpio_bit(GPIO_nFCE3, 1); break; }# else /* * Note: * assume that we can read the GPIOIOUT */ unsigned int _fce = chipnr_to_gpiobit[chip & 0xf]; unsigned int gpioiout = GPIOIOUT & 0xfff0; GPIOIOUT = (gpioiout | _fce);# endif#endif /* USE_CPU_FCE */}static int mp2520f_nand_device_ready(struct mtd_info *mtd){#if USE_CPU_RnB DPRINTK("%s():\n", __FUNCTION__); if ((MEMNANDCTRL & NAND_READY_DETECT) == NAND_READY_DETECT) { while ( MEMNANDCTRL & NAND_READY_DETECT) { MEMNANDCTRL |= NAND_READY_DETECT; } return 1; } return 0;#else udelay(1); /* T.T */ return read_gpio_bit(GPIO_RnB) ? 1 : 0;#endif}/* small and normal page size */static void mp2520f_nand_cmdfunc(struct mtd_info *mtd, unsigned command, int column, int page_addr){ register struct nand_chip *this = mtd->priv; DPRINTK("%s(): options = 0x%0x\n", __FUNCTION__, this->options); MEMNANDCTRL |= NAND_READY_DETECT; /* Adjust columns for 16 bit buswidth */ if (this->options & NAND_BUSWIDTH_16) column >>= 1; /* * Write out the command to the device. */ if (command == NAND_CMD_SEQIN) { int readcmd; if (column >= mtd->oobblock) { /* OOB area */ column -= mtd->oobblock; readcmd = NAND_CMD_READOOB; } else if (column < 256) { /* First 256 bytes --> READ0 */ readcmd = NAND_CMD_READ0; } else { column -= 256; readcmd = NAND_CMD_READ1; } NFCMD = readcmd; } NFCMD = (command & 0xFF); if (column != -1 || page_addr != -1) { /* Serially input address */ if (column != -1) NFADDR = (column & 0xFF); if (page_addr != -1) { NFADDR = (unsigned char)(page_addr & 0xff); NFADDR = (unsigned char)((page_addr >> 8) & 0xff); /* One more address cycle for higher density devices */ if (mtd->size & 0x0c000000) NFADDR = (unsigned char)((page_addr >> 16) & 0x0f); } } /* * program and erase have their own busy handlers * status and sequential in needs no delay */ switch (command) { case NAND_CMD_PAGEPROG: case NAND_CMD_ERASE1: case NAND_CMD_ERASE2: case NAND_CMD_SEQIN: case NAND_CMD_STATUS: return; case NAND_CMD_READID: /* T.T */// udelay (this->chip_delay); return; case NAND_CMD_RESET: if (this->dev_ready) break; NFCMD = NAND_CMD_STATUS; while ( !(NFDATA & 0x40)); return; /* This applies to read commands */ default: if (!this->dev_ready) { udelay (this->chip_delay); return; } } /* wait until command is processed */ while (!this->dev_ready(mtd));}/* * large page size * (not used, but ...) */static void mp2520f_nand_cmdfunc_lp(struct mtd_info *mtd, unsigned command, int column, int page_addr){ register struct nand_chip *this = mtd->priv; /* Emulate NAND_CMD_READOOB */ if (command == NAND_CMD_READOOB) { column += mtd->oobblock; command = NAND_CMD_READ0; } /* Adjust columns for 16 bit buswidth */ if (this->options & NAND_BUSWIDTH_16) column >>= 1; NFCMD = command; if (column != -1 || page_addr != -1) { /* Serially input address */ if (column != -1) { NFADDR = (column & 0xff); NFADDR = (column >> 8); } if (page_addr != -1) { NFADDR = (unsigned char) ((page_addr & 0xff)); NFADDR = (unsigned char) ((page_addr >> 8) & 0xff); /* One more address cycle for devices > 128MiB */ if (this->chipsize > (128 << 20)) NFADDR = (unsigned char) ((page_addr >> 16) & 0xff); } } /* * program and erase have their own busy handlers * status and sequential in needs no delay */ switch (command) { case NAND_CMD_CACHEDPROG: case NAND_CMD_PAGEPROG: case NAND_CMD_ERASE1: case NAND_CMD_ERASE2: case NAND_CMD_SEQIN: case NAND_CMD_STATUS: return; case NAND_CMD_READID: /* T.T */// udelay (this->chip_delay); return; case NAND_CMD_RESET: if (this->dev_ready) break; udelay(this->chip_delay); NFCMD = NAND_CMD_STATUS; while ( !(NFDATA & 0x40)); return; case NAND_CMD_READ0: NFCMD = NAND_CMD_READSTART; /* This applies to read commands */ default: /* * If we don't have access to the busy pin, we apply the given * command delay */ if (!this->dev_ready) { udelay (this->chip_delay); return; } } /* wait until command is processed */ while (!this->dev_ready(mtd));}#ifdef CONFIG_MTD_NAND_MP2520F_HWECCstatic void mp2520f_enable_hwecc(struct mtd_info *mtd, int mode){ /* do nothing */}/* * for 8bit NAND , emulate HW3_256 */static void mp2520f_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code){ *(ecc_code+1) = MEMNANDECC0 & 0xff; *(ecc_code+0) = MEMNANDECC1 & 0xff; *(ecc_code+2) = (MEMNANDECC2 & 0xff) | 0x01;}/* * for 16bit NAND , emulate HW6_512 */static void mp2520f_calculate_ecc_16(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code){ /* * FIXME - not tested */ *(ecc_code+1) = MEMNANDECC0 & 0xff; *(ecc_code+0) = MEMNANDECC1 & 0xff; *(ecc_code+2) = (MEMNANDECC2 & 0xff) | 0x01; *(ecc_code+4) = (MEMNANDECC0 >> 8) & 0xff; *(ecc_code+3) = (MEMNANDECC1 >> 8) & 0xff; *(ecc_code+4) = ((MEMNANDECC2 >> 8) & 0xff) | 0x01;}# ifdef CONFIG_MTD_NAND_MP2520F_HWECC_DEBUGstatic int mp2520f_correct_data_debug(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc){ int ret = -1; u_char dbg_ecc[3]; /* for 8-bit NAND */ nand_calculate_ecc(mtd, dat, &dbg_ecc[0]); /* * read_ecc[] : read from device OOB * calc_ecc[] : h/w ECC * dgb_ecc[] : s/w ECC */ if ((dbg_ecc[0] != calc_ecc[0]) || (dbg_ecc[1] != calc_ecc[1]) || (dbg_ecc[2] != calc_ecc[2]) || (ret = nand_correct_data(mtd, dat, read_ecc, calc_ecc))) { printk("%s():\n\tread: 0x%02x 0x%02x 0x%02x\n" "\t S/W: 0x%02x 0x%02x 0x%02x\n" "\t H/W: 0x%02x 0x%02x 0x%02x\n", __FUNCTION__, read_ecc[0], read_ecc[1], read_ecc[2], calc_ecc[0], calc_ecc[1], calc_ecc[2], dbg_ecc[0], dbg_ecc[1], dbg_ecc[2]); panic("%s(): do not use MP2520F_HWECC\n", __FUNCTION__); return ret; } return 0;}# endif /* CONFIG_MTD_NAND_MP2520F_HWECC_DEBUG */#endif /* CONFIG_MTD_NAND_MP2520F_HWECC *//* Internal buffers. Page buffer and oob buffer for one block */static u_char data_buf[2048 + 64]; /* maximum */static u_char oob_buf[64 * 32]; /* FIXME */int mp2520f_nand_init (void){ struct nand_chip *this; int err = 0;#if USE_CPU_FCE == 0 set_gpio_ctrl(GPIO_nFCE0, GPIOMD_OUT, GPIOPU_NOSET); set_gpio_ctrl(GPIO_nFCE1, GPIOMD_OUT, GPIOPU_NOSET); set_gpio_ctrl(GPIO_nFCE2, GPIOMD_OUT, GPIOPU_NOSET); set_gpio_ctrl(GPIO_nFCE3, GPIOMD_OUT, GPIOPU_NOSET); /* deselect all chips */ write_gpio_bit(GPIO_nFCE0, 1); write_gpio_bit(GPIO_nFCE1, 1); write_gpio_bit(GPIO_nFCE2, 1); write_gpio_bit(GPIO_nFCE3, 1);#endif /* USE_CPU_FCE */#if USE_CPU_RnB == 0 set_gpio_ctrl(GPIO_RnB, GPIOMD_IN, GPIOPU_NOSET);#endif /* Allocate memory for MTD device structure and private data */ mp2520f_nand_mtd = vmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip)); if (!mp2520f_nand_mtd) { printk ("Unable to allocate NAND MTD device structure.\n"); err = -ENOMEM; goto out; } /* Get pointer to private data */ this = (struct nand_chip *) (&mp2520f_nand_mtd[1]); /* Initialize structures */ memset((char *) mp2520f_nand_mtd, 0, sizeof(struct mtd_info)); memset((char *) this, 0, sizeof(struct nand_chip)); /* Link the private data with the MTD structure */ mp2520f_nand_mtd->priv = this; /* Set address of NAND IO lines */#ifdef CONFIG_MMSP2_SHADOW_ENABLE this->IO_ADDR_R = 0x9c000000; this->IO_ADDR_W = 0x9c000000;#else this->IO_ADDR_R = 0x1c000000; this->IO_ADDR_W = 0x1c000000;#endif /* CONFIG_MMSP2_SHADOW_ENABLE */ this->select_chip = mp2520f_nand_select_chip; this->dev_ready = mp2520f_nand_device_ready; this->cmdfunc = mp2520f_nand_cmdfunc;#ifdef CONFIG_MTD_NAND_MP2520F_HWECC this->calculate_ecc = mp2520f_calculate_ecc; // mp2520f_calculate_ecc_16 this->enable_hwecc = mp2520f_enable_hwecc; this->eccmode = NAND_ECC_HW3_256; // NAND_ECC_HW6_512# ifdef CONFIG_MTD_NAND_MP2520F_HWECC_DEBUG this->correct_data = mp2520f_correct_data_debug; printk(__FILE__": Using NAND H/W ECC, debug mode\n");# else this->correct_data = nand_correct_data; printk(__FILE__": Using NAND H/W ECC\n");# endif /* CONFIG_MP2520F_HWECC_DEBUG */#else this->eccmode = NAND_ECC_SOFT; printk(__FILE__": Using NAND S/W ECC\n");#endif /* CONFIG_MP2520F_HWECC */ /* Set internal data buffer */ this->data_buf = data_buf; this->oob_buf = oob_buf; /* 20 us command delay time */ this->chip_delay = 20; /* Scan to find existance of the device */ if (nand_scan (mp2520f_nand_mtd, 1)) { err = -ENXIO; goto out_mtd; } mp2520f_nand_mtd->eccsize = this->eccsize; add_mtd_device(mp2520f_nand_mtd); goto out;out_mtd: free (mp2520f_nand_mtd);out: return err;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -