📄 hycnc_nand.c
字号:
/* * drivers/mtd/nand/hycnc_nand0.c * */#include <linux/module.h>#include <linux/mtd/mtd.h>#include <linux/mtd/nand.h>#include <linux/slab.h>#include <linux/mtd/partitions.h>#include <asm/io.h>#include <asm/arch/hardware.h>#include <asm/sizes.h>#include <linux/delay.h>#include <linux/init.h>#include <asm/errno.h>#define NAND0_DATA_CS (0xEA000000)#define NAND1_DATA_CS (0xEA200000)#define _NAND_CMD_CS0 (0xEA400000)#define NAND_CMD_CS0 (*(volatile unsigned char *)(_NAND_CMD_CS0))#define NAND0_NCE (1<<0)#define NAND0_CLE (1<<1)#define NAND0_ALE (1<<2)#define NAND0_NWP (1<<3)#define NAND1_NCE (1<<4)#define NAND1_CLE (1<<5)#define NAND1_ALE (1<<6)#define NAND1_NWP (1<<7)/* * MTD structure for hycnc board */static struct mtd_info *hycnc_mtd0 = NULL;static struct mtd_info *hycnc_mtd1 = NULL;/* * Define partitions for flash devices */static struct mtd_partition partition_info16k0[] = { { name: "hycnc_Nand_Flash_A_16K", offset: 0, size: 16 * SZ_1M }, { name: "hycnc_Nand_Flash A_2_16K", offset: 0 * SZ_1M, size: 0 * SZ_1M },};static struct mtd_partition partition_info32k0[] = { { name: "hycnc_Nand_Flash_A_32K", offset: 0, size: 32 * SZ_1M }, { name: "hycnc_Nand_Flash_A_2_32K", offset: 0 * SZ_1M, size: 0 * SZ_1M },};static struct mtd_partition partition_info64k0[] = { { name: "hycnc_Nand_Flash_A_64K", offset: 0, size: 64 * SZ_1M }, { name: "hycnc_Nand_Flash_A_2_64K", offset: 0 * SZ_1M, size: 0 * SZ_1M },};static struct mtd_partition partition_info128k0[] = { { name: "hycnc_Nand_Flash_A_128K", offset: 0, size: 128 * SZ_1M }, { name: "hycnc_Nand_Flash_A_2_128K", offset: 0 * SZ_1M, size: 0 * SZ_1M },};#define NUM_PARTITIONS16K0 1#define NUM_PARTITIONS32K0 1#define NUM_PARTITIONS64K0 1#define NUM_PARTITIONS128K0 1static struct mtd_partition partition_info16k1[] = { { name: "hycnc_Nand_Flash_B_16K", offset: 0, size: 16 * SZ_1M }, { name: "hycnc_Nand_Flash_B_2_16K", offset: 0 * SZ_1M, size: 0 * SZ_1M },};static struct mtd_partition partition_info32k1[] = { { name: "hycnc_Nand_Flash_B_32K", offset: 0, size: 32 * SZ_1M }, { name: "hycnc_Nand_Flash_B_2_32K", offset: 0 * SZ_1M, size: 0 * SZ_1M },};static struct mtd_partition partition_info64k1[] = { { name: "hycnc_Nand_Flash_B_64K", offset: 0, size: 64 * SZ_1M }, { name: "hycnc_Nand_Flash_B_2_64K", offset: 0 * SZ_1M, size: 0 * SZ_1M },};static struct mtd_partition partition_info128k1[] = { { name: "hycnc_Nand_Flash_B_128K", offset: 0, size: 128 * SZ_1M }, { name: "hycnc_Nand_Flash_B_2_128K", offset: 0 * SZ_1M, size: 0 * SZ_1M },};#define NUM_PARTITIONS16K1 1#define NUM_PARTITIONS32K1 1#define NUM_PARTITIONS64K1 1#define NUM_PARTITIONS128K1 1/* * hardware specific access to control-lines*/static unsigned char nand_ctrl0 = ( NAND0_NCE | NAND0_NWP | NAND1_NCE | NAND1_NWP );static void hycnc_hwcontrol0(struct mtd_info *mtd, int cmd){ switch(cmd) { case NAND_CTL_SETCLE: nand_ctrl0 |= NAND0_CLE; NAND_CMD_CS0 = nand_ctrl0; break; case NAND_CTL_CLRCLE: nand_ctrl0 &= ~NAND0_CLE; NAND_CMD_CS0 = nand_ctrl0; break; case NAND_CTL_SETALE: nand_ctrl0 |= NAND0_ALE; NAND_CMD_CS0 = nand_ctrl0; break; case NAND_CTL_CLRALE: nand_ctrl0 &= ~NAND0_ALE; NAND_CMD_CS0 = nand_ctrl0; break; case NAND_CTL_SETNCE: nand_ctrl0 &= ~NAND0_NCE; NAND_CMD_CS0 = nand_ctrl0; break; case NAND_CTL_CLRNCE: nand_ctrl0 |= NAND0_NCE; NAND_CMD_CS0 = nand_ctrl0; break; }}static void hycnc_hwcontrol1(struct mtd_info *mtd, int cmd){ switch(cmd) { case NAND_CTL_SETCLE: nand_ctrl0 |= NAND1_CLE; NAND_CMD_CS0 = nand_ctrl0; break; case NAND_CTL_CLRCLE: nand_ctrl0 &= ~NAND1_CLE; NAND_CMD_CS0 = nand_ctrl0; break; case NAND_CTL_SETALE: nand_ctrl0 |= NAND1_ALE; NAND_CMD_CS0 = nand_ctrl0; break; case NAND_CTL_CLRALE: nand_ctrl0 &= ~NAND1_ALE; NAND_CMD_CS0 = nand_ctrl0; break; case NAND_CTL_SETNCE: nand_ctrl0 &= ~NAND1_NCE; NAND_CMD_CS0 = nand_ctrl0; break; case NAND_CTL_CLRNCE: nand_ctrl0 |= NAND1_NCE; NAND_CMD_CS0 = nand_ctrl0; break; }}/** read device ready pin*/int hycnc_device_ready0(void){ return ( RNB_CS & NAND0_RNB ) ? 1 : 0;}int hycnc_device_ready1(void){ return ( RNB_CS & NAND1_RNB ) ? 1 : 0;}int hycnc_nand_delay = 20;/* * Main initialization routine */int __init hycnc_nand_init (void){ struct nand_chip *this; int err = 0; printk ("Initialising HYCNC NAND MTD devices.\n"); /* Allocate memory for MTD device structure and private data */ hycnc_mtd0 = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip), GFP_KERNEL); if (!hycnc_mtd0) { printk ("Unable to allocate hycnc NAND MTD device structure.\n"); err = -ENOMEM; goto out; } /* Get pointer to private data */ this = (struct nand_chip *) (&hycnc_mtd0[1]); /* Initialize structures */ memset((char *) hycnc_mtd0, 0, sizeof(struct mtd_info)); memset((char *) this, 0, sizeof(struct nand_chip)); /* Link the private data with the MTD structure */ hycnc_mtd0->priv = this; /* Set address of NAND IO lines */ this->IO_ADDR_R = NAND0_DATA_CS;//弊成 例措林家蔼父 霖促. this->IO_ADDR_W = NAND0_DATA_CS;//弊成 例措林家蔼父 霖促. this->hwcontrol = hycnc_hwcontrol0; //this->dev_ready = hycnc_device_ready0; //nand on board this->dev_ready = NULL; /* 20 us command delay time */ this->chip_delay = hycnc_nand_delay; this->eccmode = NAND_ECC_SOFT; /* Scan to find existance of the device */ if (nand_scan (hycnc_mtd0, 1)) { printk ("Unable to find First HYCNC NAND device.\n"); err = -ENXIO; kfree (hycnc_mtd0); goto out; } /* Allocate memory for internal data buffer */ this->data_buf = kmalloc (sizeof(u_char) * (hycnc_mtd0->oobblock + hycnc_mtd0->oobsize), GFP_KERNEL); if (!this->data_buf) { printk ("Unable to allocate First NAND data buffer for hycnc.\n"); err = -ENOMEM; kfree (hycnc_mtd0); goto out; } /* Register the partitions */ switch(hycnc_mtd0->size) { case SZ_16M: add_mtd_partitions(hycnc_mtd0, partition_info16k0, NUM_PARTITIONS16K0); break; case SZ_32M: add_mtd_partitions(hycnc_mtd0, partition_info32k0, NUM_PARTITIONS32K0); break; case SZ_64M: add_mtd_partitions(hycnc_mtd0, partition_info64k0, NUM_PARTITIONS64K0); break; case SZ_128M: add_mtd_partitions(hycnc_mtd0, partition_info128k0, NUM_PARTITIONS128K0); break; default: { printk ("Unsupported First Nand Size\n"); err = -ENXIO; goto out; } } //printk ("Initialising of First HYCNC NAND MTD was successful.\n"); /* Allocate memory for MTD device structure and private data */ hycnc_mtd1 = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip), GFP_KERNEL); if (!hycnc_mtd1) { printk ("Unable to allocate Second HYCNC NAND MTD device structure.\n"); err = -ENOMEM; goto out; } /* Get pointer to private data */ this = (struct nand_chip *) (&hycnc_mtd1[1]); /* Initialize structures */ memset((char *) hycnc_mtd1, 0, sizeof(struct mtd_info)); memset((char *) this, 0, sizeof(struct nand_chip)); /* Link the private data with the MTD structure */ hycnc_mtd1->priv = this; /* Set address of NAND IO lines */ this->IO_ADDR_R = NAND1_DATA_CS;//弊成 例措林家蔼父 霖促. this->IO_ADDR_W = NAND1_DATA_CS;//弊成 例措林家蔼父 霖促. this->hwcontrol = hycnc_hwcontrol1; //this->dev_ready = hycnc_device_ready1; //nand on board this->dev_ready = NULL; /* 20 us command delay time */ this->chip_delay = hycnc_nand_delay; this->eccmode = NAND_ECC_SOFT; /* Scan to find existance of the device */ if (nand_scan (hycnc_mtd1, 1)) { printk ("Unable to Second HYCNC NAND device.\n"); err = -ENXIO; kfree (hycnc_mtd1); goto out; } /* Allocate memory for internal data buffer */ this->data_buf = kmalloc (sizeof(u_char) * (hycnc_mtd1->oobblock + hycnc_mtd1->oobsize), GFP_KERNEL); if (!this->data_buf) { printk ("Unable to allocate Second NAND data buffer for hycnc.\n"); err = -ENOMEM; kfree (hycnc_mtd1); goto out; } /* Register the partitions */ switch(hycnc_mtd1->size) { case SZ_16M: add_mtd_partitions(hycnc_mtd1, partition_info16k1, NUM_PARTITIONS16K1); break; case SZ_32M: add_mtd_partitions(hycnc_mtd1, partition_info32k1, NUM_PARTITIONS32K1); break; case SZ_64M: add_mtd_partitions(hycnc_mtd1, partition_info64k1, NUM_PARTITIONS64K1); break; case SZ_128M: add_mtd_partitions(hycnc_mtd1, partition_info128k1, NUM_PARTITIONS128K1); break; default: { printk ("Unsupported Second Nand Size\n"); err = -ENXIO; goto out; } } //printk ("Initialising of Second HYCNC NAND MTD was successful.\n"); return 0;out: kfree (this->data_buf); return err;}module_init(hycnc_nand_init);/* * Clean up routine */#ifdef MODULEstatic void __exit hycnc_cleanup (void){ struct nand_chip *this; this = (struct nand_chip *) &hycnc_mtd0[1]; /* Unregister partitions */ del_mtd_partitions(hycnc_mtd0); /* Unregister the device */ del_mtd_device (hycnc_mtd0); /* Free internal data buffers */ kfree (this->data_buf); /* Free the MTD device structure */ kfree (hycnc_mtd0); this = (struct nand_chip *) &hycnc_mtd1[1]; /* Unregister partitions */ del_mtd_partitions(hycnc_mtd1); /* Unregister the device */ del_mtd_device (hycnc_mtd1); /* Free internal data buffers */ kfree (this->data_buf); /* Free the MTD device structure */ kfree (hycnc_mtd1);}module_exit(hycnc_cleanup);#endifMODULE_LICENSE("GPL");MODULE_AUTHOR("newboder <newboder@hybus.net>");MODULE_DESCRIPTION("Glue layer for Nand");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -