mtd: nand: fsmc: get rid of IO_ADDR_[R|W]

Remove the use of IO_ADDR_[R|W] in the fsmc_nand driver. Instead, use a
pointer to the control registers to avoid doing several arithmetic
operations (including a multiplication) each time a control register is
read or written.

All references to IO_ADDR_[R|W] are not entirely removed from the driver
as, at this time, these values are needed by the NAND core in the
default ->read/write_byte/word() hooks. These references will be
entirely removed when switching to ->exec_op(), that does not make use
of these hooks anymore.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
This commit is contained in:
Miquel Raynal 2018-02-16 15:22:47 +01:00 committed by Boris Brezillon
parent 9c3736a3de
commit 4df6ed4f0a
1 changed files with 40 additions and 56 deletions

View File

@ -103,10 +103,6 @@
#define ECC3 0x1C
#define FSMC_NAND_BANK_SZ 0x20
#define FSMC_NAND_REG(base, bank, reg) (base + FSMC_NOR_REG_SIZE + \
(FSMC_NAND_BANK_SZ * (bank)) + \
reg)
#define FSMC_BUSY_WAIT_TIMEOUT (1 * HZ)
struct fsmc_nand_timings {
@ -143,7 +139,7 @@ enum access_mode {
* @data_va: NAND port for Data.
* @cmd_va: NAND port for Command.
* @addr_va: NAND port for Address.
* @regs_va: FSMC regs base address.
* @regs_va: Registers base address for a given bank.
*/
struct fsmc_nand_data {
u32 pid;
@ -265,8 +261,6 @@ static void fsmc_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{
struct nand_chip *this = mtd_to_nand(mtd);
struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
void __iomem *regs = host->regs_va;
unsigned int bank = host->bank;
if (ctrl & NAND_CTRL_CHANGE) {
u32 pc;
@ -282,12 +276,12 @@ static void fsmc_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
this->IO_ADDR_W = host->data_va;
}
pc = readl(FSMC_NAND_REG(regs, bank, PC));
pc = readl(host->regs_va + PC);
if (ctrl & NAND_NCE)
pc |= FSMC_ENABLE;
else
pc &= ~FSMC_ENABLE;
writel_relaxed(pc, FSMC_NAND_REG(regs, bank, PC));
writel_relaxed(pc, host->regs_va + PC);
}
mb();
@ -307,8 +301,6 @@ static void fsmc_nand_setup(struct fsmc_nand_data *host,
{
uint32_t value = FSMC_DEVTYPE_NAND | FSMC_ENABLE | FSMC_WAITON;
uint32_t tclr, tar, thiz, thold, twait, tset;
unsigned int bank = host->bank;
void __iomem *regs = host->regs_va;
tclr = (tims->tclr & FSMC_TCLR_MASK) << FSMC_TCLR_SHIFT;
tar = (tims->tar & FSMC_TAR_MASK) << FSMC_TAR_SHIFT;
@ -318,18 +310,14 @@ static void fsmc_nand_setup(struct fsmc_nand_data *host,
tset = (tims->tset & FSMC_TSET_MASK) << FSMC_TSET_SHIFT;
if (host->nand.options & NAND_BUSWIDTH_16)
writel_relaxed(value | FSMC_DEVWID_16,
FSMC_NAND_REG(regs, bank, PC));
writel_relaxed(value | FSMC_DEVWID_16, host->regs_va + PC);
else
writel_relaxed(value | FSMC_DEVWID_8,
FSMC_NAND_REG(regs, bank, PC));
writel_relaxed(value | FSMC_DEVWID_8, host->regs_va + PC);
writel_relaxed(readl(FSMC_NAND_REG(regs, bank, PC)) | tclr | tar,
FSMC_NAND_REG(regs, bank, PC));
writel_relaxed(thiz | thold | twait | tset,
FSMC_NAND_REG(regs, bank, COMM));
writel_relaxed(thiz | thold | twait | tset,
FSMC_NAND_REG(regs, bank, ATTRIB));
writel_relaxed(readl(host->regs_va + PC) | tclr | tar,
host->regs_va + PC);
writel_relaxed(thiz | thold | twait | tset, host->regs_va + COMM);
writel_relaxed(thiz | thold | twait | tset, host->regs_va + ATTRIB);
}
static int fsmc_calc_timings(struct fsmc_nand_data *host,
@ -419,15 +407,13 @@ static int fsmc_setup_data_interface(struct mtd_info *mtd, int csline,
static void fsmc_enable_hwecc(struct mtd_info *mtd, int mode)
{
struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
void __iomem *regs = host->regs_va;
uint32_t bank = host->bank;
writel_relaxed(readl(FSMC_NAND_REG(regs, bank, PC)) & ~FSMC_ECCPLEN_256,
FSMC_NAND_REG(regs, bank, PC));
writel_relaxed(readl(FSMC_NAND_REG(regs, bank, PC)) & ~FSMC_ECCEN,
FSMC_NAND_REG(regs, bank, PC));
writel_relaxed(readl(FSMC_NAND_REG(regs, bank, PC)) | FSMC_ECCEN,
FSMC_NAND_REG(regs, bank, PC));
writel_relaxed(readl(host->regs_va + PC) & ~FSMC_ECCPLEN_256,
host->regs_va + PC);
writel_relaxed(readl(host->regs_va + PC) & ~FSMC_ECCEN,
host->regs_va + PC);
writel_relaxed(readl(host->regs_va + PC) | FSMC_ECCEN,
host->regs_va + PC);
}
/*
@ -439,13 +425,11 @@ static int fsmc_read_hwecc_ecc4(struct mtd_info *mtd, const uint8_t *data,
uint8_t *ecc)
{
struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
void __iomem *regs = host->regs_va;
uint32_t bank = host->bank;
uint32_t ecc_tmp;
unsigned long deadline = jiffies + FSMC_BUSY_WAIT_TIMEOUT;
do {
if (readl_relaxed(FSMC_NAND_REG(regs, bank, STS)) & FSMC_CODE_RDY)
if (readl_relaxed(host->regs_va + STS) & FSMC_CODE_RDY)
break;
else
cond_resched();
@ -456,25 +440,25 @@ static int fsmc_read_hwecc_ecc4(struct mtd_info *mtd, const uint8_t *data,
return -ETIMEDOUT;
}
ecc_tmp = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC1));
ecc_tmp = readl_relaxed(host->regs_va + ECC1);
ecc[0] = (uint8_t) (ecc_tmp >> 0);
ecc[1] = (uint8_t) (ecc_tmp >> 8);
ecc[2] = (uint8_t) (ecc_tmp >> 16);
ecc[3] = (uint8_t) (ecc_tmp >> 24);
ecc_tmp = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC2));
ecc_tmp = readl_relaxed(host->regs_va + ECC2);
ecc[4] = (uint8_t) (ecc_tmp >> 0);
ecc[5] = (uint8_t) (ecc_tmp >> 8);
ecc[6] = (uint8_t) (ecc_tmp >> 16);
ecc[7] = (uint8_t) (ecc_tmp >> 24);
ecc_tmp = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC3));
ecc_tmp = readl_relaxed(host->regs_va + ECC3);
ecc[8] = (uint8_t) (ecc_tmp >> 0);
ecc[9] = (uint8_t) (ecc_tmp >> 8);
ecc[10] = (uint8_t) (ecc_tmp >> 16);
ecc[11] = (uint8_t) (ecc_tmp >> 24);
ecc_tmp = readl_relaxed(FSMC_NAND_REG(regs, bank, STS));
ecc_tmp = readl_relaxed(host->regs_va + STS);
ecc[12] = (uint8_t) (ecc_tmp >> 16);
return 0;
@ -489,11 +473,9 @@ static int fsmc_read_hwecc_ecc1(struct mtd_info *mtd, const uint8_t *data,
uint8_t *ecc)
{
struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
void __iomem *regs = host->regs_va;
uint32_t bank = host->bank;
uint32_t ecc_tmp;
ecc_tmp = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC1));
ecc_tmp = readl_relaxed(host->regs_va + ECC1);
ecc[0] = (uint8_t) (ecc_tmp >> 0);
ecc[1] = (uint8_t) (ecc_tmp >> 8);
ecc[2] = (uint8_t) (ecc_tmp >> 16);
@ -598,18 +580,18 @@ unmap_dma:
*/
static void fsmc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
{
struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
int i;
struct nand_chip *chip = mtd_to_nand(mtd);
if (IS_ALIGNED((uint32_t)buf, sizeof(uint32_t)) &&
IS_ALIGNED(len, sizeof(uint32_t))) {
uint32_t *p = (uint32_t *)buf;
len = len >> 2;
for (i = 0; i < len; i++)
writel_relaxed(p[i], chip->IO_ADDR_W);
writel_relaxed(p[i], host->data_va);
} else {
for (i = 0; i < len; i++)
writeb_relaxed(buf[i], chip->IO_ADDR_W);
writeb_relaxed(buf[i], host->data_va);
}
}
@ -621,18 +603,18 @@ static void fsmc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
*/
static void fsmc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
{
struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
int i;
struct nand_chip *chip = mtd_to_nand(mtd);
if (IS_ALIGNED((uint32_t)buf, sizeof(uint32_t)) &&
IS_ALIGNED(len, sizeof(uint32_t))) {
uint32_t *p = (uint32_t *)buf;
len = len >> 2;
for (i = 0; i < len; i++)
p[i] = readl_relaxed(chip->IO_ADDR_R);
p[i] = readl_relaxed(host->data_va);
} else {
for (i = 0; i < len; i++)
buf[i] = readb_relaxed(chip->IO_ADDR_R);
buf[i] = readb_relaxed(host->data_va);
}
}
@ -754,13 +736,11 @@ static int fsmc_bch8_correct_data(struct mtd_info *mtd, uint8_t *dat,
{
struct nand_chip *chip = mtd_to_nand(mtd);
struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
void __iomem *regs = host->regs_va;
unsigned int bank = host->bank;
uint32_t err_idx[8];
uint32_t num_err, i;
uint32_t ecc1, ecc2, ecc3, ecc4;
num_err = (readl_relaxed(FSMC_NAND_REG(regs, bank, STS)) >> 10) & 0xF;
num_err = (readl_relaxed(host->regs_va + STS) >> 10) & 0xF;
/* no bit flipping */
if (likely(num_err == 0))
@ -803,10 +783,10 @@ static int fsmc_bch8_correct_data(struct mtd_info *mtd, uint8_t *dat,
* uint64_t array and error offset indexes are populated in err_idx
* array
*/
ecc1 = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC1));
ecc2 = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC2));
ecc3 = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC3));
ecc4 = readl_relaxed(FSMC_NAND_REG(regs, bank, STS));
ecc1 = readl_relaxed(host->regs_va + ECC1);
ecc2 = readl_relaxed(host->regs_va + ECC2);
ecc3 = readl_relaxed(host->regs_va + ECC3);
ecc4 = readl_relaxed(host->regs_va + STS);
err_idx[0] = (ecc1 >> 0) & 0x1FFF;
err_idx[1] = (ecc1 >> 13) & 0x1FFF;
@ -889,6 +869,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
struct mtd_info *mtd;
struct nand_chip *nand;
struct resource *res;
void __iomem *base;
dma_cap_mask_t mask;
int ret = 0;
u32 pid;
@ -923,9 +904,12 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
return PTR_ERR(host->cmd_va);
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fsmc_regs");
host->regs_va = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(host->regs_va))
return PTR_ERR(host->regs_va);
base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(base))
return PTR_ERR(base);
host->regs_va = base + FSMC_NOR_REG_SIZE +
(host->bank * FSMC_NAND_BANK_SZ);
host->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(host->clk)) {
@ -942,7 +926,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
* AMBA PrimeCell bus. However it is not a PrimeCell.
*/
for (pid = 0, i = 0; i < 4; i++)
pid |= (readl(host->regs_va + resource_size(res) - 0x20 + 4 * i) & 255) << (i * 8);
pid |= (readl(base + resource_size(res) - 0x20 + 4 * i) & 255) << (i * 8);
host->pid = pid;
dev_info(&pdev->dev, "FSMC device partno %03x, manufacturer %02x, "
"revision %02x, config %02x\n",