📄 s3c24a0_nand.c
字号:
/* * NAND controller on SAMSUNG S3C24A0 * * bushi@mizi.com * * 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>extern int nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc);static struct mtd_info *s3c24a0_nand_mtd = NULL;static void s3c24a0_nand_select_chip(struct mtd_info *mtd, int chip){ if (chip == 0) NANDCONT &= ~(1 << 7); else NANDCONT |= (1 << 7);}static int s3c24a0_nand_device_ready(struct mtd_info *mtd){ return (NFSTAT & NFSTAT_RnB) ? 1:0;}/* small and normal page size */static void s3c24a0_nand_cmdfunc(struct mtd_info *mtd, unsigned command, int column, int page_addr){ register struct nand_chip *this = mtd->priv; /* 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); } /* Latch in address */ } /* * 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_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 s3c24a0_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_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));}/* 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 s3c24a0_nand_init (void){ struct nand_chip *this; int err = 0; /* Allocate memory for MTD device structure and private data */ s3c24a0_nand_mtd = vmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip)); if (!s3c24a0_nand_mtd) { printk ("Unable to allocate NAND MTD device structure.\n"); err = -ENOMEM; goto out; } /* Get pointer to private data */ this = (struct nand_chip *) (&s3c24a0_nand_mtd[1]); /* Initialize structures */ memset((char *) s3c24a0_nand_mtd, 0, sizeof(struct mtd_info)); memset((char *) this, 0, sizeof(struct nand_chip)); /* Link the private data with the MTD structure */ s3c24a0_nand_mtd->priv = this; /* Disable write protect */ GPCON_M &= ~(0x3 << 8); GPCON_M |= (0x1 << 8); /* to set as output */ GPDAT |= (0x1 << 15); /* disable write protect */ /* Set address of NAND IO lines */ this->IO_ADDR_R = 0x40c00010; this->IO_ADDR_W = 0x40c00010; this->select_chip = s3c24a0_nand_select_chip; this->dev_ready = s3c24a0_nand_device_ready; this->cmdfunc = s3c24a0_nand_cmdfunc; this->eccmode = NAND_ECC_SOFT; printk(__FILE__": Using NAND S/W ECC\n"); /* 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 (s3c24a0_nand_mtd, 1)) { err = -ENXIO; goto out_mtd; } s3c24a0_nand_mtd->eccsize = this->eccsize; add_mtd_device(s3c24a0_nand_mtd); goto out;out_mtd: free (s3c24a0_nand_mtd);out: return err;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -