📄 s3c2410nd.c
字号:
/* * MTD NAND device driver for S3C2410 Development Board * based on smc.c * * 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. *//* (林) eZEX俊辑 固瘤SDK俊辑 力傍登绰 smc_s3c2410.c甫 官帕栏肺 荐沥沁嚼聪促. * www.ezex.co.kr <lsh3974@ezex.co.kr> * * 函版等 何盒篮 酒贰客 鞍嚼聪促. * - MTD 2003-6-13老磊俊 嘎眠绢 窃荐 牢磐其捞胶 函版 * - 颇萍记 困摹 炼沥 * - 窃荐 捞抚 函版 * - H/W ECC detect, S/W 沥沥 扁瓷 瘤盔 (512/3) * - nand.c * nand_read_ecc()俊辑 ECC 八荤搬苞甫 倒妨林绰 何盒捞 512/6老锭父 贸府登绊 乐扁 锭巩俊 * yaffs啊 沥惑利栏肺 牢侥登扁 困秦辑 oob_buf甫 512/3阑 贸府窍绰 何盒捞 眠啊 登菌嚼聪促. */#include <linux/slab.h>#include <linux/module.h>#include <linux/mtd/mtd.h>#include <linux/mtd/nand.h>#include <linux/mtd/compatmac.h>#include <linux/irq.h>#include <asm/io.h>#include <asm/hardware.h>#include <asm/sizes.h>#include <linux/compiler.h>#include <linux/delay.h>#include <linux/interrupt.h>#include <linux/sched.h>/* * MTD structure for S3C2410 Development Board */static struct mtd_info *s3c2410_mtd = NULL;#include <linux/mtd/partitions.h>/* nand 场何盒篮 bon 颇萍记 抛捞喉阑 困秦辑 巢败敌促. * 俺惯捞 场唱搁 场鳖瘤 犬厘矫懦巴. */static struct mtd_partition s3c2410_partitions[] = { { name: "root", // 1M ~ 28M : 0x800page ~ 0xe000page size: 6* SZ_1M, // 13M 0xd100page offset: 1*SZ_1M, // 1M //mask_flags: MTD_WRITEABLE, /* force read-only */ }, { name: "user", size: 10*SZ_1M, offset : MTDPART_OFS_APPEND, }};static void s3c2410_hwcontrol(struct mtd_info *mtd, int cmd) { switch (cmd) { case NAND_CTL_SETNCE: NFCONF &= ~NFCONF_nFCE_HIGH; break; case NAND_CTL_CLRNCE: NFCONF |= NFCONF_nFCE_HIGH; break; case NAND_CTL_SETCLE: break; case NAND_CTL_CLRCLE: break; case NAND_CTL_SETALE: break; case NAND_CTL_CLRALE: break; }}static u_char s3c2410_read_byte(struct mtd_info *mtd) { return (u_char) NFDATA;}static void s3c2410_write_byte(struct mtd_info *mtd, u_char val) { NFDATA = (u_char) val;}static void s3c2410_write_buf(struct mtd_info *mtd, const u_char *buf, int len){ int i; for(i =0; i< len; i++) NFDATA = buf[i];}static void s3c2410_read_buf(struct mtd_info *mtd, u_char *buf, int len){ int i; for(i=0; i< len; i++) buf[i] = NFDATA;}static int s3c2410_verify_buf(struct mtd_info *mtd, const u_char *buf, int len){ int i; for(i=0; i<len; i++) if(buf[i] != NFDATA) return -1; return 0; }static int s3c2410_dev_ready(struct mtd_info *mtd){ return (NFSTAT & 0x1);}static void s3c2410_command (struct mtd_info *mtd, unsigned command, int column, int page_addr){// register struct nand_chip *this = mtd->priv; /* Begin command latch cycle */ /* * 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 = (__u8)readcmd; // this->write_byte(mtd, readcmd); } NFCMD = (__u8)command; /* Set ALE and clear CLE to start address cycle */ if (column != -1 || page_addr != -1) { /* Serially input address */ if (column != -1) NFADDR = (__u8)column; if (page_addr != -1) { NFADDR = (__u8)(page_addr & 0xff); NFADDR = (__u8)((page_addr >> 8) & 0xff); /* One more address cycle for higher density devices */ if (mtd->size & 0x0c000000) NFADDR = (__u8)((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; default : break; } /* wait until command is processed */ while (!(NFSTAT&0x1));}// 3/512 H/W// nand_correct_data(..)甫 荐沥窃.// static int s3c2410_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc){ __u8 a,b,c, d1, d2, d3, bit, i; // s3c2410篮 18bit Line Parity甫 荤侩窍扁 锭巩俊 醚 林家啊 9厚飘 鞘夸窃. __u32 add; d1 = calc_ecc[0] ^ read_ecc[0]; d2 = calc_ecc[1] ^ read_ecc[1]; d3 = calc_ecc[2] ^ read_ecc[2]; if((d1 | d2 | d3) == 0) { return 0; } else { a = (d1 ^ (d1 >> 1)) & 0x55; b = (d2 ^ (d2 >> 1)) & 0x55; c = (d3 ^ (d3 >> 1)) & 0x55; // 菩府萍 俊矾 俺荐 犬牢.. 菩府萍啊 12俺 葛滴 促弗 版快父 // 坷幅甫 荐沥且 荐 乐促. if( (a ==0x55) && (b ==0x55) && (c == 0x55)) { // line parity [8] add = (((__u32)d3 & 0x2) !=0) << 9; a = 0x80; c = 0x80; // line parity [7:4] for(i=0; i<4; i++) { if(d2 & c) add |= a; a >>= 1; c >>= 2; } // line parity [3:0] c = 0x80; for(i=0; i<4; i++) { if(d1 & c) add |= a; a >>= 1; c >>= 2; } // column parity [2:0] bit = 0; b = 0x04; c = 0x80; for(i=0; i<3; i++) { if(d3 & c) bit |= b; c >>= 2; b >>= 1; } b = 0x1; a = dat[add]; a ^= ( b << bit); dat[add] = a; return 1; }else { // 菩府萍啊 茄 厚飘父 1老锭 ECC 俊矾捞促. i = 0; while(d1) { if(d1 & 0x1) i++; d1 >>= 1; } while(d2) { if(d2 & 0x1) i++; d2 >>=1; } while(d3) { if(d3 & 0x1) i++; d3 >>=1; } // ECC 俊矾捞骨肺 促矫 拌魂等 蔼栏肺 函版 if(i == 1) { read_ecc[0] = calc_ecc[0]; read_ecc[1] = calc_ecc[1]; read_ecc[2] = calc_ecc[2]; return 2; } // 2bit 捞惑 俊矾啊 八免登绢 汗备且 荐 绝绰 版快 return -1; } } return -1;}static void s3c2410_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code){ __u32 ecc, i; ecc = NFECC; *(ecc_code) = ecc &0xff; *(ecc_code+1) = (ecc & 0xff00) >> 8; *(ecc_code+2) = (ecc & 0xff0000) >> 16;// 荤侩窍瘤 臼绰 ecc绰 0xff肺 盲况狄.. s3c2410_correct_ecc俊辑 荤侩窍瘤 臼扁 锭巩俊// 狼固绝阑 荐档 乐瘤父.. 趣矫唱 窍绰 付澜俊 持绢 涤聪促. 哗档 等促绰 犬脚捞 乐栏搁// 历俊霸档 埃窜茄 汲疙阑 焊郴林矫搁 皑荤窍摆嚼聪促. // <lsh3974@ezex.co.kr> for(i=3; i<6;i++) { ecc_code[i] = 0xff; } return;}static void s3c2410_enable_hwecc(struct mtd_info *mtd, int mode){ NFCONF |= NFCONF_ECC_INIT; return;}/* * Main initialization routine */int __init s3c2410_nand_init (void){ struct nand_chip *this; u_int16_t nfconf; unsigned int result=0; /* Allocate memory for MTD device structure and private data */ s3c2410_mtd = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip), GFP_KERNEL); if (!s3c2410_mtd) { printk ("Unable to allocate S3C2410 NAND MTD device structure.\n"); return -ENOMEM; } /* Get pointer to private data */ this = (struct nand_chip *) (&s3c2410_mtd[1]); /* Initialize structures */ memset((char *) s3c2410_mtd, 0, sizeof(struct mtd_info)); memset((char *) this, 0, sizeof(struct nand_chip)); /* Link the private data with the MTD structure */ s3c2410_mtd->priv = this; /* set NAND Flash controller */ { nfconf = NFCONF; /* NAND Flash controller enable */ nfconf |= NFCONF_FCTRL_EN; /* Set flash memory timing */ nfconf &= ~NFCONF_TWRPH1; /* 0x0 */ nfconf |= NFCONF_TWRPH0_3; /* 0x3 */ nfconf &= ~NFCONF_TACLS; /* 0x0 */ NFCONF = nfconf; } /* Set address of NAND IO lines */ this->IO_ADDR_R = (unsigned long)ioremap(0x4e00000c, SZ_1K); this->IO_ADDR_W = (unsigned long)ioremap(0x4e00000c, SZ_1K); this->read_byte = s3c2410_read_byte; this->write_byte = s3c2410_write_byte; this->write_buf = s3c2410_write_buf; this->read_buf = s3c2410_read_buf; this->verify_buf = s3c2410_verify_buf; this->hwcontrol = s3c2410_hwcontrol; this->dev_ready = s3c2410_dev_ready; this->cmdfunc = s3c2410_command; this->calculate_ecc = s3c2410_calculate_ecc; this->eccmode = NAND_ECC_HW3_512; this->enable_hwecc = s3c2410_enable_hwecc; this->correct_data = s3c2410_correct_data; if(nand_scan(s3c2410_mtd, 1)) { kfree( (void*)s3c2410_mtd); return -ENXIO; } /* Allocate memory for internal data buffer */ this->data_buf = kmalloc(sizeof(u_char) * (s3c2410_mtd->oobblock + s3c2410_mtd->oobsize), GFP_KERNEL); if (!this->data_buf) { printk ("Unable to allocate NAND data buffer for S3C2410.\n"); this->data_buf = NULL; return -ENOMEM; } result= add_mtd_partitions(s3c2410_mtd,s3c2410_partitions, sizeof(s3c2410_partitions)/sizeof(s3c2410_partitions[0])); printk("this is the result of add_mtd_partitions %d \n",result); return 0;}module_init(s3c2410_nand_init);/* * Clean up routine */#ifdef MODULEstatic void __exit s3c2410_cleanup (void){ struct nand_chip *this = (struct nand_chip *) &s3c2410_mtd[1]; iounmap(this->IO_ADDR_W); iounmap(this->IO_ADDR_R); del_mtd_partitions(s3c2410_mtd); s3c2410_mtd->size = 0; if (this->data_buf != NULL) { /* Free internal data buffer */ kfree (this->data_buf); this->data_buf = NULL; } /* Free the MTD device structure */ kfree (s3c2410_mtd);}module_exit(s3c2410_cleanup);#endifMODULE_LICENSE("GPL");MODULE_AUTHOR("LSH <www.ezex.co.kr>");MODULE_DESCRIPTION("S3C2410 NAND Flash driver");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -