aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd
diff options
context:
space:
mode:
authorJosh Wu <Josh.wu@atmel.com>2014-06-10 05:50:11 -0400
committerBrian Norris <computersforpeace@gmail.com>2014-07-21 23:05:36 -0400
commite4e069347030ab0fea7304d06704fb3b64e5fe40 (patch)
tree8be0d57b3c64f5e882db5bf77bbacb0f9888e1f0 /drivers/mtd
parent72a78e3cd2c02c46ce5a3b89a2a854199e5a4820 (diff)
mtd: atmel_nand: NFC: support multiple interrupt handling
Fix the following error, which sometimes happens during the NFC data transfer: atmel_nand 80000000.nand: Time out to wait for interrupt: 0x00010000 atmel_nand 80000000.nand: something wrong, No XFR_DONE interrupt comes. The root cause is that in the interrupt handler, we read the ISR but only handle one interrupt. If more than one interrupt arrive at the same time, then the second one will be lost. During the NFC data transfer. Two NFC interrupts (NFC_CMD_DONE and NFC_XFR_DONE) may come at the same time. NFC_CMD_DONE means NFC command is sent, and NFC_XFR_DONE means NFC data is transferred. This patch can handle multiple NFC interrupts at the same time. During the NFC data transfer, we need to wait for two NFC interrupts: NFC_CMD_DONE and NFC_XFR_DONE. Also we separate the completion initialization code to a nfc_prepare_interrupt(), which is paired with nfc_wait_interrupt(). We call nfc_prepare_interrupt() before sending out nfc commands, to make sure no interrupt lost. Reported-by: Matthieu CRAPET <Matthieu.CRAPET@ingenico.com> Tested-by: Matthieu Crapet <Matthieu.Crapet@ingenico.com> Signed-off-by: Josh Wu <josh.wu@atmel.com> Signed-off-by: Brian Norris <computersforpeace@gmail.com>
Diffstat (limited to 'drivers/mtd')
-rw-r--r--drivers/mtd/nand/atmel_nand.c84
1 files changed, 62 insertions, 22 deletions
diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
index 459acf01fefe..e321c564ff05 100644
--- a/drivers/mtd/nand/atmel_nand.c
+++ b/drivers/mtd/nand/atmel_nand.c
@@ -97,7 +97,9 @@ struct atmel_nfc {
97 bool write_by_sram; 97 bool write_by_sram;
98 98
99 bool is_initialized; 99 bool is_initialized;
100 struct completion comp_nfc; 100 struct completion comp_ready;
101 struct completion comp_cmd_done;
102 struct completion comp_xfer_done;
101 103
102 /* Point to the sram bank which include readed data via NFC */ 104 /* Point to the sram bank which include readed data via NFC */
103 void __iomem *data_in_sram; 105 void __iomem *data_in_sram;
@@ -1596,44 +1598,80 @@ static irqreturn_t hsmc_interrupt(int irq, void *dev_id)
1596{ 1598{
1597 struct atmel_nand_host *host = dev_id; 1599 struct atmel_nand_host *host = dev_id;
1598 u32 status, mask, pending; 1600 u32 status, mask, pending;
1599 irqreturn_t ret = IRQ_HANDLED; 1601 irqreturn_t ret = IRQ_NONE;
1600 1602
1601 status = nfc_read_status(host); 1603 status = nfc_read_status(host);
1602 mask = nfc_readl(host->nfc->hsmc_regs, IMR); 1604 mask = nfc_readl(host->nfc->hsmc_regs, IMR);
1603 pending = status & mask; 1605 pending = status & mask;
1604 1606
1605 if (pending & NFC_SR_XFR_DONE) { 1607 if (pending & NFC_SR_XFR_DONE) {
1606 complete(&host->nfc->comp_nfc); 1608 complete(&host->nfc->comp_xfer_done);
1607 nfc_writel(host->nfc->hsmc_regs, IDR, NFC_SR_XFR_DONE); 1609 nfc_writel(host->nfc->hsmc_regs, IDR, NFC_SR_XFR_DONE);
1608 } else if (pending & NFC_SR_RB_EDGE) { 1610 ret = IRQ_HANDLED;
1609 complete(&host->nfc->comp_nfc); 1611 }
1612 if (pending & NFC_SR_RB_EDGE) {
1613 complete(&host->nfc->comp_ready);
1610 nfc_writel(host->nfc->hsmc_regs, IDR, NFC_SR_RB_EDGE); 1614 nfc_writel(host->nfc->hsmc_regs, IDR, NFC_SR_RB_EDGE);
1611 } else if (pending & NFC_SR_CMD_DONE) { 1615 ret = IRQ_HANDLED;
1612 complete(&host->nfc->comp_nfc); 1616 }
1617 if (pending & NFC_SR_CMD_DONE) {
1618 complete(&host->nfc->comp_cmd_done);
1613 nfc_writel(host->nfc->hsmc_regs, IDR, NFC_SR_CMD_DONE); 1619 nfc_writel(host->nfc->hsmc_regs, IDR, NFC_SR_CMD_DONE);
1614 } else { 1620 ret = IRQ_HANDLED;
1615 ret = IRQ_NONE;
1616 } 1621 }
1617 1622
1618 return ret; 1623 return ret;
1619} 1624}
1620 1625
1621/* NFC(Nand Flash Controller) related functions */ 1626/* NFC(Nand Flash Controller) related functions */
1622static int nfc_wait_interrupt(struct atmel_nand_host *host, u32 flag) 1627static void nfc_prepare_interrupt(struct atmel_nand_host *host, u32 flag)
1623{ 1628{
1624 unsigned long timeout; 1629 if (flag & NFC_SR_XFR_DONE)
1625 init_completion(&host->nfc->comp_nfc); 1630 init_completion(&host->nfc->comp_xfer_done);
1631
1632 if (flag & NFC_SR_RB_EDGE)
1633 init_completion(&host->nfc->comp_ready);
1634
1635 if (flag & NFC_SR_CMD_DONE)
1636 init_completion(&host->nfc->comp_cmd_done);
1626 1637
1627 /* Enable interrupt that need to wait for */ 1638 /* Enable interrupt that need to wait for */
1628 nfc_writel(host->nfc->hsmc_regs, IER, flag); 1639 nfc_writel(host->nfc->hsmc_regs, IER, flag);
1640}
1629 1641
1630 timeout = wait_for_completion_timeout(&host->nfc->comp_nfc, 1642static int nfc_wait_interrupt(struct atmel_nand_host *host, u32 flag)
1631 msecs_to_jiffies(NFC_TIME_OUT_MS)); 1643{
1632 if (timeout) 1644 int i, index = 0;
1633 return 0; 1645 struct completion *comp[3]; /* Support 3 interrupt completion */
1646
1647 if (flag & NFC_SR_XFR_DONE)
1648 comp[index++] = &host->nfc->comp_xfer_done;
1649
1650 if (flag & NFC_SR_RB_EDGE)
1651 comp[index++] = &host->nfc->comp_ready;
1634 1652
1635 /* Time out to wait for the interrupt */ 1653 if (flag & NFC_SR_CMD_DONE)
1654 comp[index++] = &host->nfc->comp_cmd_done;
1655
1656 if (index == 0) {
1657 dev_err(host->dev, "Unkown interrupt flag: 0x%08x\n", flag);
1658 return -EINVAL;
1659 }
1660
1661 for (i = 0; i < index; i++) {
1662 if (wait_for_completion_timeout(comp[i],
1663 msecs_to_jiffies(NFC_TIME_OUT_MS)))
1664 continue; /* wait for next completion */
1665 else
1666 goto err_timeout;
1667 }
1668
1669 return 0;
1670
1671err_timeout:
1636 dev_err(host->dev, "Time out to wait for interrupt: 0x%08x\n", flag); 1672 dev_err(host->dev, "Time out to wait for interrupt: 0x%08x\n", flag);
1673 /* Disable the interrupt as it is not handled by interrupt handler */
1674 nfc_writel(host->nfc->hsmc_regs, IDR, flag);
1637 return -ETIMEDOUT; 1675 return -ETIMEDOUT;
1638} 1676}
1639 1677
@@ -1641,6 +1679,9 @@ static int nfc_send_command(struct atmel_nand_host *host,
1641 unsigned int cmd, unsigned int addr, unsigned char cycle0) 1679 unsigned int cmd, unsigned int addr, unsigned char cycle0)
1642{ 1680{
1643 unsigned long timeout; 1681 unsigned long timeout;
1682 u32 flag = NFC_SR_CMD_DONE;
1683 flag |= cmd & NFCADDR_CMD_DATAEN ? NFC_SR_XFR_DONE : 0;
1684
1644 dev_dbg(host->dev, 1685 dev_dbg(host->dev,
1645 "nfc_cmd: 0x%08x, addr1234: 0x%08x, cycle0: 0x%02x\n", 1686 "nfc_cmd: 0x%08x, addr1234: 0x%08x, cycle0: 0x%02x\n",
1646 cmd, addr, cycle0); 1687 cmd, addr, cycle0);
@@ -1654,9 +1695,11 @@ static int nfc_send_command(struct atmel_nand_host *host,
1654 return -ETIMEDOUT; 1695 return -ETIMEDOUT;
1655 } 1696 }
1656 } 1697 }
1698
1699 nfc_prepare_interrupt(host, flag);
1657 nfc_writel(host->nfc->hsmc_regs, CYCLE0, cycle0); 1700 nfc_writel(host->nfc->hsmc_regs, CYCLE0, cycle0);
1658 nfc_cmd_addr1234_writel(cmd, addr, host->nfc->base_cmd_regs); 1701 nfc_cmd_addr1234_writel(cmd, addr, host->nfc->base_cmd_regs);
1659 return nfc_wait_interrupt(host, NFC_SR_CMD_DONE); 1702 return nfc_wait_interrupt(host, flag);
1660} 1703}
1661 1704
1662static int nfc_device_ready(struct mtd_info *mtd) 1705static int nfc_device_ready(struct mtd_info *mtd)
@@ -1822,10 +1865,6 @@ static void nfc_nand_command(struct mtd_info *mtd, unsigned int command,
1822 nfc_addr_cmd = cmd1 | cmd2 | vcmd2 | acycle | csid | dataen | nfcwr; 1865 nfc_addr_cmd = cmd1 | cmd2 | vcmd2 | acycle | csid | dataen | nfcwr;
1823 nfc_send_command(host, nfc_addr_cmd, addr1234, cycle0); 1866 nfc_send_command(host, nfc_addr_cmd, addr1234, cycle0);
1824 1867
1825 if (dataen == NFCADDR_CMD_DATAEN)
1826 if (nfc_wait_interrupt(host, NFC_SR_XFR_DONE))
1827 dev_err(host->dev, "something wrong, No XFR_DONE interrupt comes.\n");
1828
1829 /* 1868 /*
1830 * Program and erase have their own busy handlers status, sequential 1869 * Program and erase have their own busy handlers status, sequential
1831 * in, and deplete1 need no delay. 1870 * in, and deplete1 need no delay.
@@ -1850,6 +1889,7 @@ static void nfc_nand_command(struct mtd_info *mtd, unsigned int command,
1850 } 1889 }
1851 /* fall through */ 1890 /* fall through */
1852 default: 1891 default:
1892 nfc_prepare_interrupt(host, NFC_SR_RB_EDGE);
1853 nfc_wait_interrupt(host, NFC_SR_RB_EDGE); 1893 nfc_wait_interrupt(host, NFC_SR_RB_EDGE);
1854 } 1894 }
1855} 1895}