📄 nand.patch
字号:
return 0; } +static void au1xxx_nand_select_chip(struct mtd_info *mtd, int chip)+{+ switch(chip) {+ case -1:+ /* deassert chip enable */+ au_writel(au_readl(MEM_STNDCTL) & ~(1<<(4+NAND_CS)), MEM_STNDCTL);+ break;+ case 0:+ /* assert (force assert) chip enable */+ au_writel(au_readl(MEM_STNDCTL) | (1<<(4+NAND_CS)) , MEM_STNDCTL);+ break;++ default:+ BUG();+ }+} -static void au1550_hwcontrol(struct mtd_info *mtd, int cmd)+static void au1xxx_nand_command (struct mtd_info *mtd, unsigned command,+ int column, int page_addr) { register struct nand_chip *this = mtd->priv; - switch(cmd){+ /*+ * Write out the command to the device.+ */+ if (command == NAND_CMD_SEQIN) {+ int readcmd; - case NAND_CTL_SETCLE: this->IO_ADDR_W = p_nand + MEM_STNAND_CMD; break;- case NAND_CTL_CLRCLE: this->IO_ADDR_W = p_nand + MEM_STNAND_DATA; break;+ 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;+ }+ write_cmd_reg(readcmd);+ }+ write_cmd_reg(command);++ if (column != -1 || page_addr != -1) {++ /* Serially input address */+ if (column != -1)+ write_addr_reg(column);+ if (page_addr != -1) {+ write_addr_reg((unsigned char) (page_addr & 0xff));+ write_addr_reg(((page_addr >> 8) & 0xff));+ /* One more address cycle for higher density devices */+ if (mtd->size & 0x0c000000)+ write_addr_reg((unsigned char) ((page_addr >> 16) & 0x0f));+ }+ } - case NAND_CTL_SETALE: this->IO_ADDR_W = p_nand + MEM_STNAND_ADDR; break;- case NAND_CTL_CLRALE: - this->IO_ADDR_W = p_nand + MEM_STNAND_DATA; - /* FIXME: Nobody knows why this is neccecary, - * but it works only that way */- udelay(1); + switch (command) {++ case NAND_CMD_PAGEPROG:+ case NAND_CMD_ERASE1:+ case NAND_CMD_ERASE2:+ case NAND_CMD_SEQIN:+ case NAND_CMD_STATUS: break; - case NAND_CTL_SETNCE: - /* assert (force assert) chip enable */- au_writel((1<<(4+NAND_CS)) , MEM_STNDCTL); break;+ case NAND_CMD_RESET:+ if (this->dev_ready) break;+ udelay(this->chip_delay);+ write_cmd_reg(NAND_CMD_STATUS);+ while ( !(read_data_reg() & 0x40));+ return; - case NAND_CTL_CLRNCE: - /* deassert chip enable */- au_writel(0, MEM_STNDCTL); break;- break;+ /* This applies to read commands */+ default:+ udelay (this->chip_delay); } - this->IO_ADDR_R = this->IO_ADDR_W;- - /* Drain the writebuffer */- au_sync();+ /* wait until command is processed */+ while (!this->dev_ready(mtd)); } -int au1550_device_ready(struct mtd_info *mtd)-{- int ret = (au_readl(MEM_STSTAT) & 0x1) ? 1 : 0;- au_sync();- return ret;-} /* * Main initialization routine */-int __init au1550_init (void)+int __init au1xxx_nand_init (void) { struct nand_chip *this; u16 boot_swapboot = 0; /* default value */- int retval;+ u32 mem_staddr;+ u32 nand_phys; /* Allocate memory for MTD device structure and private data */- au1550_mtd = kmalloc (sizeof(struct mtd_info) + + au1xxx_nand_mtd = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip), GFP_KERNEL);- if (!au1550_mtd) {+ if (!au1xxx_nand_mtd) { printk ("Unable to allocate NAND MTD dev structure.\n"); return -ENOMEM; } /* Get pointer to private data */- this = (struct nand_chip *) (&au1550_mtd[1]);+ this = (struct nand_chip *) (&au1xxx_nand_mtd[1]); /* Initialize structures */- memset((char *) au1550_mtd, 0, sizeof(struct mtd_info));+ memset((char *) au1xxx_nand_mtd, 0, sizeof(struct mtd_info)); memset((char *) this, 0, sizeof(struct nand_chip)); /* Link the private data with the MTD structure */- au1550_mtd->priv = this;+ au1xxx_nand_mtd->priv = this; + /* disable interrupts */+ au_writel(au_readl(MEM_STNDCTL) & ~(1<<8), MEM_STNDCTL); - /* MEM_STNDCTL: disable ints, disable nand boot */- au_writel(0, MEM_STNDCTL);+ /* disable NAND boot */+ au_writel(au_readl(MEM_STNDCTL) & ~(1<<0), MEM_STNDCTL); #ifdef CONFIG_MIPS_PB1550 /* set gpio206 high */ au_writel(au_readl(GPIO2_DIR) & ~(1<<6), GPIO2_DIR); + /* Pb1550: check boot configuration to make sure NAND is visible */ boot_swapboot = (au_readl(MEM_STSTAT) & (0x7<<1)) | ((bcsr->status >> 6) & 0x1); switch (boot_swapboot) {@@ -381,6 +302,7 @@ int __init au1550_init (void) case 0xD: /* x16 NAND Flash */ nand_width = 0;+ printk("Pb1550 NAND: 16-bit NAND not supported by MTD\n"); break; case 1: case 9:@@ -392,86 +314,123 @@ int __init au1550_init (void) break; default: printk("Pb1550 NAND: bad boot:swap\n");- retval = -EINVAL;- goto outmem;+ kfree(au1xxx_nand_mtd);+ return 1; } #endif - /* Configure RCE1 - should be done by YAMON */- au_writel(0x5 | (nand_width << 22), 0xB4001010); /* MEM_STCFG1 */- au_writel(NAND_TIMING, 0xB4001014); /* MEM_STTIME1 */- au_sync();-- /* setup and enable chip select, MEM_STADDR1 */- /* we really need to decode offsets only up till 0x20 */- au_writel((1<<28) | (NAND_PHYS_ADDR>>4) | - (((NAND_PHYS_ADDR + 0x1000)-1) & (0x3fff<<18)>>18), - MEM_STADDR1);- au_sync();+ /* Configure chip-select; normally done by boot code, e.g. YAMON */+#ifdef NAND_STCFG+ if (NAND_CS == 0) {+ au_writel(NAND_STCFG, MEM_STCFG0);+ au_writel(NAND_STTIME, MEM_STTIME0);+ au_writel(NAND_STADDR, MEM_STADDR0);+ }+ if (NAND_CS == 1) {+ au_writel(NAND_STCFG, MEM_STCFG1);+ au_writel(NAND_STTIME, MEM_STTIME1);+ au_writel(NAND_STADDR, MEM_STADDR1);+ }+ if (NAND_CS == 2) {+ au_writel(NAND_STCFG, MEM_STCFG2);+ au_writel(NAND_STTIME, MEM_STTIME2);+ au_writel(NAND_STADDR, MEM_STADDR2);+ }+ if (NAND_CS == 3) {+ au_writel(NAND_STCFG, MEM_STCFG3);+ au_writel(NAND_STTIME, MEM_STTIME3);+ au_writel(NAND_STADDR, MEM_STADDR3);+ }+#endif - p_nand = ioremap(NAND_PHYS_ADDR, 0x1000);+ /* Locate NAND chip-select in order to determine NAND physical address */+ mem_staddr = 0x00000000;+ if (((au_readl(MEM_STCFG0) & 0x7) == 0x5) && (NAND_CS == 0))+ mem_staddr = au_readl(MEM_STADDR0);+ else+ if (((au_readl(MEM_STCFG1) & 0x7) == 0x5) && (NAND_CS == 1))+ mem_staddr = au_readl(MEM_STADDR1);+ else+ if (((au_readl(MEM_STCFG2) & 0x7) == 0x5) && (NAND_CS == 2))+ mem_staddr = au_readl(MEM_STADDR2);+ else+ if (((au_readl(MEM_STCFG3) & 0x7) == 0x5) && (NAND_CS == 3))+ mem_staddr = au_readl(MEM_STADDR3);++ if (mem_staddr == 0x00000000) {+ printk("Au1xxx NAND: ERROR WITH NAND CHIP-SELECT\n");+ kfree(au1xxx_nand_mtd);+ return 1;+ }+ nand_phys = (mem_staddr << 4) & 0xFFFC0000;++ p_nand = (volatile struct nand_regs *)ioremap(nand_phys, 0x1000);++ /* make controller and MTD agree */+ if (NAND_CS == 0)+ nand_width = au_readl(MEM_STCFG0) & (1<<22);+ if (NAND_CS == 1)+ nand_width = au_readl(MEM_STCFG1) & (1<<22);+ if (NAND_CS == 2)+ nand_width = au_readl(MEM_STCFG2) & (1<<22);+ if (NAND_CS == 3)+ nand_width = au_readl(MEM_STCFG3) & (1<<22); /* Set address of hardware control function */- this->hwcontrol = au1550_hwcontrol;- this->dev_ready = au1550_device_ready;+ this->hwcontrol = au1xxx_hwcontrol;+ this->dev_ready = au1xxx_device_ready; /* 30 us command delay time */ this->chip_delay = 30; - this->eccmode = NAND_ECC_SOFT;-- this->options = NAND_NO_AUTOINCR; - if (!nand_width)- this->options |= NAND_BUSWIDTH_16;+ this->cmdfunc = au1xxx_nand_command;+ this->select_chip = au1xxx_nand_select_chip;+ this->write_byte = au1xxx_nand_write_byte;+ this->read_byte = au1xxx_nand_read_byte;+ this->write_buf = au1xxx_nand_write_buf;+ this->read_buf = au1xxx_nand_read_buf;+ this->verify_buf = au1xxx_nand_verify_buf;+ this->eccmode = NAND_ECC_SOFT; - this->read_byte = (!nand_width) ? au_read_byte16 : au_read_byte;- this->write_byte = (!nand_width) ? au_write_byte16 : au_write_byte;- this->write_word = au_write_word;- this->read_word = au_read_word;- this->write_buf = (!nand_width) ? au_write_buf16 : au_write_buf;- this->read_buf = (!nand_width) ? au_read_buf16 : au_read_buf;- this->verify_buf = (!nand_width) ? au_verify_buf16 : au_verify_buf;+ /* Set internal data buffer */+ this->data_buf = data_buf;+ this->oob_buf = oob_buf; /* Scan to find existence of the device */- if (nand_scan (au1550_mtd, 1)) {- retval = -ENXIO;- goto outio;+ if (nand_scan (au1xxx_nand_mtd, 1)) {+ kfree (au1xxx_nand_mtd);+ return -ENXIO; } /* Register the partitions */- add_mtd_partitions(au1550_mtd, partition_info, NUM_PARTITIONS);+ add_mtd_partitions(au1xxx_nand_mtd, partition_info, NB_OF(partition_info)); return 0;-- outio:- iounmap ((void *)p_nand);- - outmem:- kfree (au1550_mtd);- return retval; } -module_init(au1550_init);+module_init(au1xxx_nand_init); /* * Clean up routine */ #ifdef MODULE-static void __exit au1550_cleanup (void)+static void __exit au1xxx_nand_cleanup (void) {- struct nand_chip *this = (struct nand_chip *) &au1550_mtd[1];+ struct nand_chip *this = (struct nand_chip *) &au1xxx_nand_mtd[1]; - /* Release resources, unregister device */- nand_release (au1550_mtd);+ iounmap ((void *)p_nand); - /* Free the MTD device structure */- kfree (au1550_mtd);+ /* Unregister partitions */+ del_mtd_partitions(au1xxx_nand_mtd); - /* Unmap */- iounmap ((void *)p_nand);+ /* Unregister the device */+ del_mtd_device (au1xxx_nand_mtd);++ /* Free the MTD device structure */+ kfree (au1xxx_nand_mtd); }-module_exit(au1550_cleanup);+module_exit(au1xxx_nand_cleanup); #endif MODULE_LICENSE("GPL"); MODULE_AUTHOR("Embedded Edge, LLC");-MODULE_DESCRIPTION("Board-specific glue layer for NAND flash on Pb1550 board");+MODULE_DESCRIPTION("NAND flash support for Alchemy");diff -rwbupN linux26-cvs/drivers/mtd/nand/Kconfig linux26-nand/drivers/mtd/nand/Kconfig--- linux26-cvs/drivers/mtd/nand/Kconfig 2005-06-14 23:48:19.000000000 -0500+++ linux26-nand/drivers/mtd/nand/Kconfig 2005-06-15 00:04:36.260027624 -0500@@ -73,11 +73,11 @@ config MTD_NAND_TX4938NDFMC Toshiba RBTX4938 reference board. config MTD_NAND_AU1550- tristate "Au1550 NAND support"- depends on SOC_AU1550 && MTD_NAND+ tristate "Au1550/1200 NAND support"+ depends on (SOC_AU1200 || SOC_AU1550) && MTD_NAND help This enables the driver for the NAND flash controller on the- AMD/Alchemy 1550 SOC.+ AMD/Alchemy 1550/1200 SOC . config MTD_NAND_RTC_FROM4 tristate "Renesas Flash ROM 4-slot interface board (FROM_BOARD4)"
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -