lantiq: nand fixes

Signed-off-by: John Crispin <blogic@openwrt.org>

SVN-Revision: 40372
This commit is contained in:
John Crispin 2014-04-03 14:27:02 +00:00
parent 15139d468c
commit a05356f48a
2 changed files with 223 additions and 0 deletions

View file

@ -0,0 +1,86 @@
From patchwork Wed Apr 2 19:38:31 2014
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Subject: [OpenWrt-Devel,
3/7] lantiq: BT Home Hub 2B support - nand driver locking
Date: Wed, 02 Apr 2014 18:38:31 -0000
From: Ben Mulvihill <ben.mulvihill@gmail.com>
X-Patchwork-Id: 5112
Message-Id: <1396467511.31327.41.camel@merveille.lan>
To: openwrt-devel@lists.openwrt.org
As a result of changeset 40310, the xway nand driver
now acquires ebu_lock in the chip select function, and
holds it for the entire duration of an operation until
the chip is deselected. There is surely no longer any
need therefore also to acquire the lock in each separate
read or write function. This patch removes that code.
Signed-off-by: Ben Mulvihill <ben.mulvihill@gmail.com>
---
--- a/drivers/mtd/nand/xway_nand.c 2014-04-01 20:14:53.072824371 +0200
+++ b/drivers/mtd/nand/xway_nand.c 2014-04-01 21:24:52.798612391 +0200
@@ -102,7 +102,6 @@ static void xway_cmd_ctrl(struct mtd_inf
{
struct nand_chip *this = mtd->priv;
unsigned long nandaddr = (unsigned long) this->IO_ADDR_W;
- unsigned long flags;
if (ctrl & NAND_CTRL_CHANGE) {
if (ctrl & NAND_CLE)
@@ -112,11 +111,9 @@ static void xway_cmd_ctrl(struct mtd_inf
}
if (cmd != NAND_CMD_NONE) {
- spin_lock_irqsave(&ebu_lock, flags);
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);
}
}
@@ -129,12 +126,9 @@ static unsigned char xway_read_byte(stru
{
struct nand_chip *this = mtd->priv;
unsigned long nandaddr = (unsigned long) this->IO_ADDR_R;
- unsigned long flags;
int ret;
- spin_lock_irqsave(&ebu_lock, flags);
ret = ltq_r8((void __iomem *)(nandaddr | NAND_READ_DATA));
- spin_unlock_irqrestore(&ebu_lock, flags);
return ret;
}
@@ -143,26 +137,20 @@ static void xway_read_buf(struct mtd_inf
{
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)

View file

@ -0,0 +1,137 @@
From patchwork Wed Apr 2 19:38:52 2014
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Subject: [OpenWrt-Devel,
4/7] lantiq: BT Home Hub 2B support - nand pci interference
Date: Wed, 02 Apr 2014 18:38:52 -0000
From: Ben Mulvihill <ben.mulvihill@gmail.com>
X-Patchwork-Id: 5113
Message-Id: <1396467532.31327.42.camel@merveille.lan>
To: openwrt-devel@lists.openwrt.org
Prevents interference between the xway nand driver and pci.
(Based on work by Simon Hayes first published on www.psidoc.com and
http://sourceforge.net/projects/hh2b4ever/)
Signed-off-by: Ben Mulvihill <ben.mulvihill@gmail.com>
---
--- a/drivers/mtd/nand/xway_nand.c 2014-04-01 21:24:52.798612391 +0200
+++ a/drivers/mtd/nand/xway_nand.c 2014-04-01 21:20:33.924585096 +0200
@@ -54,8 +54,27 @@
#define NAND_CON_CSMUX (1 << 1)
#define NAND_CON_NANDM 1
+#define DANUBE_PCI_REG32( addr ) (*(volatile u32 *)(addr))
+#define PCI_CR_PR_OFFSET (KSEG1+0x1E105400)
+#define PCI_CR_PC_ARB (PCI_CR_PR_OFFSET + 0x0080)
+
static u32 xway_latchcmd;
+/*
+ * req_mask provides a mechanism to prevent interference between
+ * nand and pci (probably only relevant for the BT Home Hub 2B).
+ * Setting it causes the corresponding pci req pins to be masked
+ * during nand access, and also moves ebu locking from the read/write
+ * functions to the chip select function to ensure that the whole
+ * operation runs with interrupts disabled.
+ * In addition it switches on some extra waiting in xway_cmd_ctrl().
+ * This seems to be necessary if the ebu_cs1 pin has open-drain disabled,
+ * which in turn seems to be necessary for the nor chip to be recognised
+ * reliably, on a board (Home Hub 2B again) which has both nor and nand.
+ */
+
+static __be32 req_mask = 0;
+
static void xway_reset_chip(struct nand_chip *chip)
{
unsigned long nandaddr = (unsigned long) chip->IO_ADDR_W;
@@ -86,12 +105,24 @@ static void xway_select_chip(struct mtd_
case -1:
ltq_ebu_w32_mask(NAND_CON_CE, 0, EBU_NAND_CON);
ltq_ebu_w32_mask(NAND_CON_NANDM, 0, EBU_NAND_CON);
+
+ if (req_mask) {
+ /* Unmask all external PCI request */
+ DANUBE_PCI_REG32(PCI_CR_PC_ARB) &= ~(req_mask << 16);
+ }
spin_unlock_irqrestore(&ebu_lock, csflags);
+
break;
case 0:
spin_lock_irqsave(&ebu_lock, csflags);
+ if (req_mask) {
+ /* Mask all external PCI request */
+ DANUBE_PCI_REG32(PCI_CR_PC_ARB) |= (req_mask << 16);
+ }
+
ltq_ebu_w32_mask(0, NAND_CON_NANDM, EBU_NAND_CON);
ltq_ebu_w32_mask(0, NAND_CON_CE, EBU_NAND_CON);
+
break;
default:
BUG();
@@ -103,6 +134,12 @@ static void xway_cmd_ctrl(struct mtd_inf
struct nand_chip *this = mtd->priv;
unsigned long nandaddr = (unsigned long) this->IO_ADDR_W;
+ if (req_mask) {
+ if (cmd != NAND_CMD_STATUS)
+ ltq_ebu_w32(EBU_NAND_WAIT, 0); /* Clear nand ready */
+ }
+
+
if (ctrl & NAND_CTRL_CHANGE) {
if (ctrl & NAND_CLE)
xway_latchcmd = NAND_WRITE_CMD;
@@ -115,6 +152,24 @@ static void xway_cmd_ctrl(struct mtd_inf
while ((ltq_ebu_r32(EBU_NAND_WAIT) & NAND_WAIT_WR_C) == 0)
;
}
+
+ if (req_mask) {
+ /*
+ * program and erase have their own busy handlers
+ * status and sequential in needs no delay
+ */
+ switch (cmd) {
+ case NAND_CMD_ERASE1:
+ case NAND_CMD_SEQIN:
+ case NAND_CMD_STATUS:
+ case NAND_CMD_READID:
+ return;
+ }
+
+ /* wait until command is processed */
+ while ((ltq_ebu_r32(EBU_NAND_WAIT) & NAND_WAIT_RD) == 0)
+ ;
+ }
}
static int xway_dev_ready(struct mtd_info *mtd)
@@ -157,6 +212,8 @@ static int xway_nand_probe(struct platfo
{
struct nand_chip *this = platform_get_drvdata(pdev);
unsigned long nandaddr = (unsigned long) this->IO_ADDR_W;
+ const __be32 *req_mask_ptr = of_get_property(pdev->dev.of_node,
+ "req-mask", NULL);
const __be32 *cs = of_get_property(pdev->dev.of_node,
"lantiq,cs", NULL);
u32 cs_flag = 0;
@@ -165,6 +222,12 @@ static int xway_nand_probe(struct platfo
if (cs && (*cs == 1))
cs_flag = NAND_CON_IN_CS1 | NAND_CON_OUT_CS1;
+ /*
+ * Load the PCI req lines to mask from the device tree. If the
+ * property is not present, setting req_mask to 0 disables masking.
+ */
+ req_mask = (req_mask_ptr ? *req_mask_ptr : 0);
+
/* setup the EBU to run in NAND mode on our base addr */
ltq_ebu_w32(CPHYSADDR(nandaddr)
| ADDSEL1_MASK(3) | ADDSEL1_REGEN, EBU_ADDSEL1);