mtd/drivers/mtd/nand au1550nd.c,1.6,1.7
gleixner at infradead.org
gleixner at infradead.org
Wed Sep 1 19:36:13 EDT 2004
Update of /home/cvs/mtd/drivers/mtd/nand
In directory phoenix.infradead.org:/tmp/cvs-serv18790
Modified Files:
au1550nd.c
Log Message:
resubmit the crappy driver. thats ugly but it works. look only at the busy loop after program and erase. bah. If I have some more time I will ask Othmar to do some tests and we make it work proper
Index: au1550nd.c
===================================================================
RCS file: /home/cvs/mtd/drivers/mtd/nand/au1550nd.c,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -r1.6 -r1.7
--- au1550nd.c 27 Aug 2004 14:21:28 -0000 1.6
+++ au1550nd.c 1 Sep 2004 23:36:10 -0000 1.7
@@ -32,7 +32,7 @@
*/
static struct mtd_info *au1550_mtd = NULL;
static volatile u32 p_nand;
-static int nand_width = 1; /* default x8*/
+static int nand_width = 1; /* default, only x8 supported for now */
/*
* Define partitions for flash device
@@ -66,49 +66,195 @@
#endif
};
+static inline void write_cmd_reg(u8 cmd)
+{
+ if (nand_width)
+ *((volatile u8 *)(p_nand + MEM_STNAND_CMD)) = cmd;
+ else
+ *((volatile u16 *)(p_nand + MEM_STNAND_CMD)) = cmd;
+ au_sync();
+}
+
+static inline void write_addr_reg(u8 addr)
+{
+ if (nand_width)
+ *((volatile u8 *)(p_nand + MEM_STNAND_ADDR)) = addr;
+ else
+ *((volatile u16 *)(p_nand + MEM_STNAND_ADDR)) = addr;
+ au_sync();
+}
+
+static inline void write_data_reg(u8 data)
+{
+ if (nand_width)
+ *((volatile u8 *)(p_nand + MEM_STNAND_DATA)) = data;
+ else
+ *((volatile u16 *)(p_nand + MEM_STNAND_DATA)) = data;
+ au_sync();
+}
+
+static inline u32 read_data_reg(void)
+{
+ u32 data;
+ if (nand_width) {
+ data = *((volatile u8 *)(p_nand + MEM_STNAND_DATA));
+ au_sync();
+ }
+ else {
+ data = *((volatile u16 *)(p_nand + MEM_STNAND_DATA));
+ au_sync();
+ }
+ return data;
+}
+
void au1550_hwcontrol(struct mtd_info *mtd, int cmd)
{
- register struct nand_chip *this = mtd->priv;
+}
- switch(cmd){
+int au1550_device_ready(struct mtd_info *mtd)
+{
+ int ready;
+ ready = (au_readl(MEM_STSTAT) & 0x1) ? 1 : 0;
+ return ready;
+}
- case NAND_CTL_SETCLE: this->IO_ADDR_W = p_nand + MEM_STNAND_CMD;
- case NAND_CTL_CLRCLE: this->IO_ADDR_W = p_nand + MEM_STNAND_DATA;
+static u_char au1550_nand_read_byte(struct mtd_info *mtd)
+{
+ u_char ret;
+ ret = read_data_reg();
+ return ret;
+}
- case NAND_CTL_SETALE: this->IO_ADDR_W = p_nand + MEM_STNAND_ADDR;
- case NAND_CTL_CLRALE: this->IO_ADDR_W = p_nand + MEM_STNAND_DATA;
+static void au1550_nand_write_byte(struct mtd_info *mtd, u_char byte)
+{
+ write_data_reg((u8)byte);
+}
+
+static void
+au1550_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
+{
+ int i;
+
+ for (i=0; i<len; i++)
+ write_data_reg(buf[i]);
+}
+
+static void
+au1550_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+{
+ int i;
+
+ for (i=0; i<len; i++)
+ buf[i] = (u_char)read_data_reg();
+}
- case NAND_CTL_SETNCE:
+static int
+au1550_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
+{
+ int i;
+
+ for (i=0; i<len; i++)
+ if (buf[i] != (u_char)read_data_reg())
+ return -EFAULT;
+
+ return 0;
+}
+
+static void au1550_nand_select_chip(struct mtd_info *mtd, int chip)
+{
+ switch(chip) {
+ case -1:
+ /* deassert chip enable */
+ au_writel(au_readl(MEM_STNDCTL) & ~0x20 , MEM_STNDCTL);
+ break;
+ case 0:
/* assert (force assert) chip enable */
au_writel(au_readl(MEM_STNDCTL) | 0x20 , MEM_STNDCTL);
break;
- case NAND_CTL_CLRNCE:
- /* deassert chip enable */
- au_writel(au_readl(MEM_STNDCTL) & ~0x20 , MEM_STNDCTL);
- break;
+ default:
+ BUG();
}
-
- this->IO_ADDR_R = this->IO_ADDR_W;
-
- /* Drain the io/pipeline */
- au_sync();
}
-int au1550_device_ready(struct mtd_info *mtd)
+static void au1550_nand_command (struct mtd_info *mtd, unsigned command,
+ int column, int page_addr)
{
- return (au_readl(MEM_STSTAT) & 0x1) ? 1 : 0;
+ register struct nand_chip *this = mtd->priv;
+
+ /*
+ * 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;
+ }
+ 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));
+ }
+ }
+
+ 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_CMD_RESET:
+ if (this->dev_ready)
+ break;
+ udelay(this->chip_delay);
+ write_cmd_reg(NAND_CMD_STATUS);
+ while ( !(read_data_reg() & 0x40));
+ return;
+
+ /* This applies to read commands */
+ default:
+ udelay (this->chip_delay);
+ }
+
+ /* wait until command is processed */
+ while (!this->dev_ready(mtd));
}
+
/*
* Main initialization routine
*/
int __init au1550_init (void)
{
struct nand_chip *this;
+#ifdef CONFIG_MIPS_PB1550
u16 boot_swapboot = 0; /* default value */
u32 mem_time;
- int retval;
+#endif
+ int retval = -EIO;
/* Allocate memory for MTD device structure and private data */
au1550_mtd = kmalloc (sizeof(struct mtd_info) +
@@ -148,6 +294,7 @@
case 0xD:
/* x16 NAND Flash */
nand_width = 0;
+ printk("Pb1550 NAND: 16-bit NAND not supported by MTD\n");
break;
case 1:
case 9:
@@ -159,8 +306,8 @@
break;
default:
printk("Pb1550 NAND: bad boot:swap\n");
- retval = -EINVAL;
- goto outmem;
+ kfree(au1550_mtd);
+ return 1;
}
/* Configure RCE1 - should be done by YAMON */
@@ -183,6 +330,9 @@
* this as it does not work with all chips.
* someone should look into the correct timing
* values, as bit 8 does a clock / 4 prescale
+ *
+ * FIXME: THis is bootloader stuff.
+ *
*/
au_writel(0x00400105, MEM_STCFG1);
au_writel(0x00007774, MEM_STTIME1);
@@ -190,18 +340,23 @@
#endif
p_nand = (volatile struct nand_regs *)ioremap(NAND_PHYS_ADDR, 0x1000);
+ if (!p_nand)
+ goto outmem;
/* Set address of hardware control function */
this->hwcontrol = au1550_hwcontrol;
this->dev_ready = au1550_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 = au1550_nand_command;
+ this->select_chip = au1550_nand_select_chip;
+ this->write_byte = au1550_nand_write_byte;
+ this->read_byte = au1550_nand_read_byte;
+ this->write_buf = au1550_nand_write_buf;
+ this->read_buf = au1550_nand_read_buf;
+ this->verify_buf = au1550_nand_verify_buf;
+ this->eccmode = NAND_ECC_SOFT;
/* Scan to find existence of the device */
if (nand_scan (au1550_mtd, 1)) {
More information about the linux-mtd-cvs
mailing list