From cc77f36d2ea812027dc2a8a94c788c4c145f82dc Mon Sep 17 00:00:00 2001 From: John Crispin Date: Mon, 22 Oct 2012 10:25:39 +0200 Subject: [PATCH 33/40] MTD: lantiq: xway: make nand actually work http://lists.infradead.org/pipermail/linux-mtd/2012-September/044240.html Signed-off-by: John Crispin --- drivers/mtd/nand/xway_nand.c | 54 +++++++++++++++++++++++++++++++++++------- 1 file changed, 45 insertions(+), 9 deletions(-) --- a/drivers/mtd/nand/xway_nand.c +++ b/drivers/mtd/nand/xway_nand.c @@ -54,19 +54,29 @@ #define NAND_CON_CSMUX (1 << 1) #define NAND_CON_NANDM 1 +static u32 xway_latchcmd; + static void xway_reset_chip(struct nand_chip *chip) { unsigned long nandaddr = (unsigned long) chip->IO_ADDR_W; unsigned long flags; + unsigned long timeout; nandaddr &= ~NAND_WRITE_ADDR; nandaddr |= NAND_WRITE_CMD; /* finish with a reset */ + timeout = jiffies + msecs_to_jiffies(200); + spin_lock_irqsave(&ebu_lock, flags); + writeb(NAND_WRITE_CMD_RESET, (void __iomem *) nandaddr); - while ((ltq_ebu_r32(EBU_NAND_WAIT) & NAND_WAIT_WR_C) == 0) - ; + do { + if ((ltq_ebu_r32(EBU_NAND_WAIT) & NAND_WAIT_WR_C) == 0) + break; + cond_resched(); + } while (!time_after_eq(jiffies, timeout)); + spin_unlock_irqrestore(&ebu_lock, flags); } @@ -94,17 +104,15 @@ static void xway_cmd_ctrl(struct mtd_inf unsigned long flags; if (ctrl & NAND_CTRL_CHANGE) { - nandaddr &= ~(NAND_WRITE_CMD | NAND_WRITE_ADDR); if (ctrl & NAND_CLE) - nandaddr |= NAND_WRITE_CMD; - else - nandaddr |= NAND_WRITE_ADDR; - this->IO_ADDR_W = (void __iomem *) nandaddr; + xway_latchcmd = NAND_WRITE_CMD; + else if (ctrl & NAND_ALE) + xway_latchcmd = NAND_WRITE_ADDR; } if (cmd != NAND_CMD_NONE) { spin_lock_irqsave(&ebu_lock, flags); - writeb(cmd, this->IO_ADDR_W); + writeb(cmd, (void __iomem *) (nandaddr | xway_latchcmd)); while ((ltq_ebu_r32(EBU_NAND_WAIT) & NAND_WAIT_WR_C) == 0) ; spin_unlock_irqrestore(&ebu_lock, flags); @@ -124,12 +132,38 @@ static unsigned char xway_read_byte(stru int ret; spin_lock_irqsave(&ebu_lock, flags); - ret = ltq_r8((void __iomem *)(nandaddr + NAND_READ_DATA)); + ret = ltq_r8((void __iomem *)(nandaddr | NAND_READ_DATA)); spin_unlock_irqrestore(&ebu_lock, flags); return ret; } +static void xway_read_buf(struct mtd_info *mtd, u_char *buf, int len) +{ + struct nand_chip *this = mtd->priv; + unsigned long nandaddr = (unsigned long) this->IO_ADDR_R; + unsigned long flags; + int i; + + spin_lock_irqsave(&ebu_lock, flags); + for (i = 0; i < len; i++) + buf[i] = ltq_r8((void __iomem *)(nandaddr | NAND_READ_DATA)); + spin_unlock_irqrestore(&ebu_lock, flags); +} + +static void xway_write_buf(struct mtd_info *mtd, const u_char *buf, int len) +{ + struct nand_chip *this = mtd->priv; + unsigned long nandaddr = (unsigned long) this->IO_ADDR_W; + unsigned long flags; + int i; + + spin_lock_irqsave(&ebu_lock, flags); + for (i = 0; i < len; i++) + ltq_w8(buf[i], (void __iomem *)nandaddr); + spin_unlock_irqrestore(&ebu_lock, flags); +} + static int xway_nand_probe(struct platform_device *pdev) { struct nand_chip *this = platform_get_drvdata(pdev); @@ -175,6 +209,8 @@ static struct platform_nand_data xway_na .dev_ready = xway_dev_ready, .select_chip = xway_select_chip, .read_byte = xway_read_byte, + .read_buf = xway_read_buf, + .write_buf = xway_write_buf, } };