mtd: nand: sunxi: improve ->cmd_ctrl() function

Try to pack address and command cycles into a single NAND controller
command to avoid polling the status register for each single change
on the NAND bus.

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
This commit is contained in:
Boris Brezillon 2015-09-16 09:05:31 +02:00
parent fe82ccefc9
commit e9aa671f69

View File

@ -238,6 +238,10 @@ struct sunxi_nand_chip {
u32 timing_cfg;
u32 timing_ctl;
int selected;
int addr_cycles;
u32 addr[2];
int cmd_cycles;
u8 cmd[2];
int nsels;
struct sunxi_nand_chip_sel sels[0];
};
@ -525,17 +529,49 @@ static void sunxi_nfc_cmd_ctrl(struct mtd_info *mtd, int dat,
writel(tmp, nfc->regs + NFC_REG_CTL);
}
if (dat == NAND_CMD_NONE)
return;
if (dat == NAND_CMD_NONE && (ctrl & NAND_NCE) &&
!(ctrl & (NAND_CLE | NAND_ALE))) {
u32 cmd = 0;
if (ctrl & NAND_CLE) {
writel(NFC_SEND_CMD1 | dat, nfc->regs + NFC_REG_CMD);
} else {
writel(dat, nfc->regs + NFC_REG_ADDR_LOW);
writel(NFC_SEND_ADR, nfc->regs + NFC_REG_CMD);
if (!sunxi_nand->addr_cycles && !sunxi_nand->cmd_cycles)
return;
if (sunxi_nand->cmd_cycles--)
cmd |= NFC_SEND_CMD1 | sunxi_nand->cmd[0];
if (sunxi_nand->cmd_cycles--) {
cmd |= NFC_SEND_CMD2;
writel(sunxi_nand->cmd[1],
nfc->regs + NFC_REG_RCMD_SET);
}
sunxi_nand->cmd_cycles = 0;
if (sunxi_nand->addr_cycles) {
cmd |= NFC_SEND_ADR |
NFC_ADR_NUM(sunxi_nand->addr_cycles);
writel(sunxi_nand->addr[0],
nfc->regs + NFC_REG_ADDR_LOW);
}
if (sunxi_nand->addr_cycles > 4)
writel(sunxi_nand->addr[1],
nfc->regs + NFC_REG_ADDR_HIGH);
writel(cmd, nfc->regs + NFC_REG_CMD);
sunxi_nand->addr[0] = 0;
sunxi_nand->addr[1] = 0;
sunxi_nand->addr_cycles = 0;
sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0);
}
sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0);
if (ctrl & NAND_CLE) {
sunxi_nand->cmd[sunxi_nand->cmd_cycles++] = dat;
} else if (ctrl & NAND_ALE) {
sunxi_nand->addr[sunxi_nand->addr_cycles / 4] |=
dat << ((sunxi_nand->addr_cycles % 4) * 8);
sunxi_nand->addr_cycles++;
}
}
/* These seed values have been extracted from Allwinner's BSP */