X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;f=qemu%2Froms%2Fu-boot%2Fdrivers%2Fmtd%2Fnand%2Ffsl_upm.c;fp=qemu%2Froms%2Fu-boot%2Fdrivers%2Fmtd%2Fnand%2Ffsl_upm.c;h=3ae0044f26e8ba42bbb429cc542e68a2e9fa4a45;hb=e44e3482bdb4d0ebde2d8b41830ac2cdb07948fb;hp=0000000000000000000000000000000000000000;hpb=9ca8dbcc65cfc63d6f5ef3312a33184e1d726e00;p=kvmfornfv.git diff --git a/qemu/roms/u-boot/drivers/mtd/nand/fsl_upm.c b/qemu/roms/u-boot/drivers/mtd/nand/fsl_upm.c new file mode 100644 index 000000000..3ae0044f2 --- /dev/null +++ b/qemu/roms/u-boot/drivers/mtd/nand/fsl_upm.c @@ -0,0 +1,199 @@ +/* + * FSL UPM NAND driver + * + * Copyright (C) 2007 MontaVista Software, Inc. + * Anton Vorontsov + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include + +static void fsl_upm_start_pattern(struct fsl_upm *upm, u32 pat_offset) +{ + clrsetbits_be32(upm->mxmr, MxMR_MAD_MSK, MxMR_OP_RUNP | pat_offset); + (void)in_be32(upm->mxmr); +} + +static void fsl_upm_end_pattern(struct fsl_upm *upm) +{ + clrbits_be32(upm->mxmr, MxMR_OP_RUNP); + + while (in_be32(upm->mxmr) & MxMR_OP_RUNP) + eieio(); +} + +static void fsl_upm_run_pattern(struct fsl_upm *upm, int width, + void __iomem *io_addr, u32 mar) +{ + out_be32(upm->mar, mar); + (void)in_be32(upm->mar); + switch (width) { + case 8: + out_8(io_addr, 0x0); + break; + case 16: + out_be16(io_addr, 0x0); + break; + case 32: + out_be32(io_addr, 0x0); + break; + } +} + +static void fun_wait(struct fsl_upm_nand *fun) +{ + if (fun->dev_ready) { + while (!fun->dev_ready(fun->chip_nr)) + debug("unexpected busy state\n"); + } else { + /* + * If the R/B pin is not connected, + * a short delay is necessary. + */ + udelay(1); + } +} + +#if CONFIG_SYS_NAND_MAX_CHIPS > 1 +static void fun_select_chip(struct mtd_info *mtd, int chip_nr) +{ + struct nand_chip *chip = mtd->priv; + struct fsl_upm_nand *fun = chip->priv; + + if (chip_nr >= 0) { + fun->chip_nr = chip_nr; + chip->IO_ADDR_R = chip->IO_ADDR_W = + fun->upm.io_addr + fun->chip_offset * chip_nr; + } else if (chip_nr == -1) { + chip->cmd_ctrl(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE); + } +} +#endif + +static void fun_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) +{ + struct nand_chip *chip = mtd->priv; + struct fsl_upm_nand *fun = chip->priv; + void __iomem *io_addr; + u32 mar; + + if (!(ctrl & fun->last_ctrl)) { + fsl_upm_end_pattern(&fun->upm); + + if (cmd == NAND_CMD_NONE) + return; + + fun->last_ctrl = ctrl & (NAND_ALE | NAND_CLE); + } + + if (ctrl & NAND_CTRL_CHANGE) { + if (ctrl & NAND_ALE) + fsl_upm_start_pattern(&fun->upm, fun->upm_addr_offset); + else if (ctrl & NAND_CLE) + fsl_upm_start_pattern(&fun->upm, fun->upm_cmd_offset); + } + + mar = cmd << (32 - fun->width); + io_addr = fun->upm.io_addr; +#if CONFIG_SYS_NAND_MAX_CHIPS > 1 + if (fun->chip_nr > 0) { + io_addr += fun->chip_offset * fun->chip_nr; + if (fun->upm_mar_chip_offset) + mar |= fun->upm_mar_chip_offset * fun->chip_nr; + } +#endif + fsl_upm_run_pattern(&fun->upm, fun->width, io_addr, mar); + + /* + * Some boards/chips needs this. At least the MPC8360E-RDK + * needs it. Probably weird chip, because I don't see any + * need for this on MPC8555E + Samsung K9F1G08U0A. Usually + * here are 0-2 unexpected busy states per block read. + */ + if (fun->wait_flags & FSL_UPM_WAIT_RUN_PATTERN) + fun_wait(fun); +} + +static u8 upm_nand_read_byte(struct mtd_info *mtd) +{ + struct nand_chip *chip = mtd->priv; + + return in_8(chip->IO_ADDR_R); +} + +static void upm_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len) +{ + int i; + struct nand_chip *chip = mtd->priv; + struct fsl_upm_nand *fun = chip->priv; + + for (i = 0; i < len; i++) { + out_8(chip->IO_ADDR_W, buf[i]); + if (fun->wait_flags & FSL_UPM_WAIT_WRITE_BYTE) + fun_wait(fun); + } + + if (fun->wait_flags & FSL_UPM_WAIT_WRITE_BUFFER) + fun_wait(fun); +} + +static void upm_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) +{ + int i; + struct nand_chip *chip = mtd->priv; + + for (i = 0; i < len; i++) + buf[i] = in_8(chip->IO_ADDR_R); +} + +static int upm_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len) +{ + int i; + struct nand_chip *chip = mtd->priv; + + for (i = 0; i < len; i++) { + if (buf[i] != in_8(chip->IO_ADDR_R)) + return -EFAULT; + } + + return 0; +} + +static int nand_dev_ready(struct mtd_info *mtd) +{ + struct nand_chip *chip = mtd->priv; + struct fsl_upm_nand *fun = chip->priv; + + return fun->dev_ready(fun->chip_nr); +} + +int fsl_upm_nand_init(struct nand_chip *chip, struct fsl_upm_nand *fun) +{ + if (fun->width != 8 && fun->width != 16 && fun->width != 32) + return -ENOSYS; + + fun->last_ctrl = NAND_CLE; + + chip->priv = fun; + chip->chip_delay = fun->chip_delay; + chip->ecc.mode = NAND_ECC_SOFT; + chip->cmd_ctrl = fun_cmd_ctrl; +#if CONFIG_SYS_NAND_MAX_CHIPS > 1 + chip->select_chip = fun_select_chip; +#endif + chip->read_byte = upm_nand_read_byte; + chip->read_buf = upm_nand_read_buf; + chip->write_buf = upm_nand_write_buf; + chip->verify_buf = upm_nand_verify_buf; + if (fun->dev_ready) + chip->dev_ready = nand_dev_ready; + + return 0; +}