On Fri, Jul 11, 2025 at 5:19 PM Tom Rini <tr...@konsulko.com> wrote:
> As no platforms use this driver anymore let's go ahead and remove it. > > Signed-off-by: Tom Rini <tr...@konsulko.com> > --- > drivers/mtd/nand/raw/Kconfig | 16 - > drivers/mtd/nand/raw/Makefile | 2 - > drivers/mtd/nand/raw/octeontx_bch.c | 422 ---- > drivers/mtd/nand/raw/octeontx_bch.h | 131 -- > drivers/mtd/nand/raw/octeontx_bch_regs.h | 167 -- > drivers/mtd/nand/raw/octeontx_nand.c | 2254 ---------------------- > 6 files changed, 2992 deletions(-) > delete mode 100644 drivers/mtd/nand/raw/octeontx_bch.c > delete mode 100644 drivers/mtd/nand/raw/octeontx_bch.h > delete mode 100644 drivers/mtd/nand/raw/octeontx_bch_regs.h > delete mode 100644 drivers/mtd/nand/raw/octeontx_nand.c > > Reviewed-by: Michael Trimarchi <mich...@amarulasolutions.com> diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig > index 4b4330302bed..492b577709d0 100644 > --- a/drivers/mtd/nand/raw/Kconfig > +++ b/drivers/mtd/nand/raw/Kconfig > @@ -567,22 +567,6 @@ config NAND_ZYNQ_USE_BOOTLOADER1_TIMINGS > This flag prevent U-Boot reconfigure NAND flash controller and > reuse > the NAND timing from 1st stage bootloader. > > -config NAND_OCTEONTX > - bool "Support for OcteonTX NAND controller" > - select SYS_NAND_SELF_INIT > - imply CMD_NAND > - help > - This enables Nand flash controller hardware found on the OcteonTX > - processors. > - > -config NAND_OCTEONTX_HW_ECC > - bool "Support Hardware ECC for OcteonTX NAND controller" > - depends on NAND_OCTEONTX > - default y > - help > - This enables Hardware BCH engine found on the OcteonTX > processors to > - support ECC for NAND flash controller. > - > config NAND_STM32_FMC2 > bool "Support for NAND controller on STM32MP SoCs" > depends on ARCH_STM32MP > diff --git a/drivers/mtd/nand/raw/Makefile b/drivers/mtd/nand/raw/Makefile > index 5ffd450e8fe7..76546a6287b7 100644 > --- a/drivers/mtd/nand/raw/Makefile > +++ b/drivers/mtd/nand/raw/Makefile > @@ -66,8 +66,6 @@ obj-$(CONFIG_NAND_MESON) += meson_nand.o > obj-$(CONFIG_NAND_MXC) += mxc_nand.o > obj-$(CONFIG_NAND_MXS) += mxs_nand.o > obj-$(CONFIG_NAND_MXS_DT) += mxs_nand_dt.o > -obj-$(CONFIG_NAND_OCTEONTX) += octeontx_nand.o > -obj-$(CONFIG_NAND_OCTEONTX_HW_ECC) += octeontx_bch.o > obj-$(CONFIG_NAND_PXA3XX) += pxa3xx_nand.o > obj-$(CONFIG_TEGRA_NAND) += tegra_nand.o > obj-$(CONFIG_NAND_OMAP_GPMC) += omap_gpmc.o > diff --git a/drivers/mtd/nand/raw/octeontx_bch.c > b/drivers/mtd/nand/raw/octeontx_bch.c > deleted file mode 100644 > index 056a6857822f..000000000000 > --- a/drivers/mtd/nand/raw/octeontx_bch.c > +++ /dev/null > @@ -1,422 +0,0 @@ > -// SPDX-License-Identifier: GPL-2.0 > -/* > - * Copyright (C) 2018 Marvell International Ltd. > - */ > - > -#include <dm.h> > -#include <dm/of_access.h> > -#include <malloc.h> > -#include <memalign.h> > -#include <nand.h> > -#include <pci.h> > -#include <pci_ids.h> > -#include <time.h> > -#include <linux/bitfield.h> > -#include <linux/ctype.h> > -#include <linux/delay.h> > -#include <linux/errno.h> > -#include <linux/err.h> > -#include <linux/ioport.h> > -#include <linux/libfdt.h> > -#include <linux/mtd/mtd.h> > -#include <linux/mtd/nand_bch.h> > -#include <linux/mtd/nand_ecc.h> > -#include <asm/io.h> > -#include <asm/types.h> > -#include <asm/dma-mapping.h> > -#include <asm/arch/clock.h> > -#include "octeontx_bch.h" > - > -static LIST_HEAD(octeontx_bch_devices); > -static unsigned int num_vfs = BCH_NR_VF; > -static void *bch_pf; > -static void *bch_vf; > -static void *token; > -static bool bch_pf_initialized; > -static bool bch_vf_initialized; > - > -static int pci_enable_sriov(struct udevice *dev, int nr_virtfn) > -{ > - int ret; > - > - ret = pci_sriov_init(dev, nr_virtfn); > - if (ret) > - printf("%s(%s): pci_sriov_init returned %d\n", __func__, > - dev->name, ret); > - return ret; > -} > - > -void *octeontx_bch_getv(void) > -{ > - if (!bch_vf) > - return NULL; > - if (bch_vf_initialized && bch_pf_initialized) > - return bch_vf; > - else > - return NULL; > -} > - > -void octeontx_bch_putv(void *token) > -{ > - bch_vf_initialized = !!token; > - bch_vf = token; > -} > - > -void *octeontx_bch_getp(void) > -{ > - return token; > -} > - > -void octeontx_bch_putp(void *token) > -{ > - bch_pf = token; > - bch_pf_initialized = !!token; > -} > - > -static int do_bch_init(struct bch_device *bch) > -{ > - return 0; > -} > - > -static void bch_reset(struct bch_device *bch) > -{ > - writeq(1, bch->reg_base + BCH_CTL); > - mdelay(2); > -} > - > -static void bch_disable(struct bch_device *bch) > -{ > - writeq(~0ull, bch->reg_base + BCH_ERR_INT_ENA_W1C); > - writeq(~0ull, bch->reg_base + BCH_ERR_INT); > - bch_reset(bch); > -} > - > -static u32 bch_check_bist_status(struct bch_device *bch) > -{ > - return readq(bch->reg_base + BCH_BIST_RESULT); > -} > - > -static int bch_device_init(struct bch_device *bch) > -{ > - u64 bist; > - int rc; > - > - debug("%s: Resetting...\n", __func__); > - /* Reset the PF when probed first */ > - bch_reset(bch); > - > - debug("%s: Checking BIST...\n", __func__); > - /* Check BIST status */ > - bist = (u64)bch_check_bist_status(bch); > - if (bist) { > - dev_err(dev, "BCH BIST failed with code 0x%llx\n", bist); > - return -ENODEV; > - } > - > - /* Get max VQs/VFs supported by the device */ > - > - bch->max_vfs = pci_sriov_get_totalvfs(bch->dev); > - debug("%s: %d vfs\n", __func__, bch->max_vfs); > - if (num_vfs > bch->max_vfs) { > - dev_warn(dev, "Num of VFs to enable %d is greater than max > available. Enabling %d VFs.\n", > - num_vfs, bch->max_vfs); > - num_vfs = bch->max_vfs; > - } > - bch->vfs_enabled = bch->max_vfs; > - /* Get number of VQs/VFs to be enabled */ > - /* TODO: Get CLK frequency */ > - /* Reset device parameters */ > - > - debug("%s: Doing initialization\n", __func__); > - rc = do_bch_init(bch); > - > - return rc; > -} > - > -static int bch_sriov_configure(struct udevice *dev, int numvfs) > -{ > - struct bch_device *bch = dev_get_priv(dev); > - int ret = -EBUSY; > - > - debug("%s(%s, %d), bch: %p, vfs_in_use: %d, enabled: %d\n", > __func__, > - dev->name, numvfs, bch, bch->vfs_in_use, bch->vfs_enabled); > - if (bch->vfs_in_use) > - goto exit; > - > - ret = 0; > - > - if (numvfs > 0) { > - debug("%s: Enabling sriov\n", __func__); > - ret = pci_enable_sriov(dev, numvfs); > - if (ret == 0) { > - bch->flags |= BCH_FLAG_SRIOV_ENABLED; > - ret = numvfs; > - bch->vfs_enabled = numvfs; > - } > - } > - > - debug("VFs enabled: %d\n", ret); > -exit: > - debug("%s: Returning %d\n", __func__, ret); > - return ret; > -} > - > -static int octeontx_pci_bchpf_probe(struct udevice *dev) > -{ > - struct bch_device *bch; > - int ret; > - > - debug("%s(%s)\n", __func__, dev->name); > - bch = dev_get_priv(dev); > - if (!bch) > - return -ENOMEM; > - > - bch->reg_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, 0, 0, > - PCI_REGION_TYPE, PCI_REGION_MEM); > - bch->dev = dev; > - > - debug("%s: base address: %p\n", __func__, bch->reg_base); > - ret = bch_device_init(bch); > - if (ret) { > - printf("%s(%s): init returned %d\n", __func__, dev->name, > ret); > - return ret; > - } > - INIT_LIST_HEAD(&bch->list); > - list_add(&bch->list, &octeontx_bch_devices); > - token = (void *)dev; > - > - debug("%s: Configuring SRIOV\n", __func__); > - bch_sriov_configure(dev, num_vfs); > - debug("%s: Done.\n", __func__); > - octeontx_bch_putp(bch); > - > - return 0; > -} > - > -static const struct pci_device_id octeontx_bchpf_pci_id_table[] = { > - { PCI_VDEVICE(CAVIUM, PCI_DEVICE_ID_CAVIUM_BCH) }, > - {}, > -}; > - > -static const struct pci_device_id octeontx_bchvf_pci_id_table[] = { > - { PCI_VDEVICE(CAVIUM, PCI_DEVICE_ID_CAVIUM_BCHVF)}, > - {}, > -}; > - > -/** > - * Given a data block calculate the ecc data and fill in the response > - * > - * @param[in] block 8-byte aligned pointer to data block to calculate > ECC > - * @param block_size Size of block in bytes, must be a multiple of two. > - * @param bch_level Number of errors that must be corrected. The > number of > - * parity bytes is equal to ((15 * bch_level) + 7) / > 8. > - * Must be 4, 8, 16, 24, 32, 40, 48, 56, 60 or 64. > - * @param[out] ecc 8-byte aligned pointer to where ecc data should go > - * @param[in] resp pointer to where responses will be written. > - * > - * Return: Zero on success, negative on failure. > - */ > -int octeontx_bch_encode(struct bch_vf *vf, dma_addr_t block, u16 > block_size, > - u8 bch_level, dma_addr_t ecc, dma_addr_t resp) > -{ > - union bch_cmd cmd; > - int rc; > - > - memset(&cmd, 0, sizeof(cmd)); > - cmd.s.cword.ecc_gen = eg_gen; > - cmd.s.cword.ecc_level = bch_level; > - cmd.s.cword.size = block_size; > - > - cmd.s.oword.ptr = ecc; > - cmd.s.iword.ptr = block; > - cmd.s.rword.ptr = resp; > - rc = octeontx_cmd_queue_write(QID_BCH, 1, > - sizeof(cmd) / sizeof(uint64_t), > cmd.u); > - if (rc) > - return -1; > - > - octeontx_bch_write_doorbell(1, vf); > - > - return 0; > -} > - > -/** > - * Given a data block and ecc data correct the data block > - * > - * @param[in] block_ecc_in 8-byte aligned pointer to data block with > ECC > - * data concatenated to the end to correct > - * @param block_size Size of block in bytes, must be a multiple > of > - * two. > - * @param bch_level Number of errors that must be corrected. > The > - * number of parity bytes is equal to > - * ((15 * bch_level) + 7) / 8. > - * Must be 4, 8, 16, 24, 32, 40, 48, 56, 60 > or 64. > - * @param[out] block_out 8-byte aligned pointer to corrected data > buffer. > - * This should not be the same as > block_ecc_in. > - * @param[in] resp pointer to where responses will be written. > - * > - * Return: Zero on success, negative on failure. > - */ > - > -int octeontx_bch_decode(struct bch_vf *vf, dma_addr_t block_ecc_in, > - u16 block_size, u8 bch_level, > - dma_addr_t block_out, dma_addr_t resp) > -{ > - union bch_cmd cmd; > - int rc; > - > - memset(&cmd, 0, sizeof(cmd)); > - cmd.s.cword.ecc_gen = eg_correct; > - cmd.s.cword.ecc_level = bch_level; > - cmd.s.cword.size = block_size; > - > - cmd.s.oword.ptr = block_out; > - cmd.s.iword.ptr = block_ecc_in; > - cmd.s.rword.ptr = resp; > - rc = octeontx_cmd_queue_write(QID_BCH, 1, > - sizeof(cmd) / sizeof(uint64_t), > cmd.u); > - if (rc) > - return -1; > - > - octeontx_bch_write_doorbell(1, vf); > - return 0; > -} > -EXPORT_SYMBOL(octeontx_bch_decode); > - > -int octeontx_bch_wait(struct bch_vf *vf, union bch_resp *resp, > - dma_addr_t handle) > -{ > - ulong start = get_timer(0); > - > - __iormb(); /* HW is updating *resp */ > - while (!resp->s.done && get_timer(start) < 10) > - __iormb(); /* HW is updating *resp */ > - > - if (resp->s.done) > - return 0; > - > - return -ETIMEDOUT; > -} > - > -struct bch_q octeontx_bch_q[QID_MAX]; > - > -static int octeontx_cmd_queue_initialize(struct udevice *dev, int > queue_id, > - int max_depth, int fpa_pool, > - int pool_size) > -{ > - /* some params are for later merge with CPT or cn83xx */ > - struct bch_q *q = &octeontx_bch_q[queue_id]; > - unsigned long paddr; > - u64 *chunk_buffer; > - int chunk = max_depth + 1; > - int i, size; > - > - if ((unsigned int)queue_id >= QID_MAX) > - return -EINVAL; > - if (max_depth & chunk) /* must be 2^N - 1 */ > - return -EINVAL; > - > - size = NQS * chunk * sizeof(u64); > - chunk_buffer = dma_alloc_coherent(size, &paddr); > - if (!chunk_buffer) > - return -ENOMEM; > - > - q->base_paddr = paddr; > - q->dev = dev; > - q->index = 0; > - q->max_depth = max_depth; > - q->pool_size_m1 = pool_size; > - q->base_vaddr = chunk_buffer; > - > - for (i = 0; i < NQS; i++) { > - u64 *ixp; > - int inext = (i + 1) * chunk - 1; > - int j = (i + 1) % NQS; > - int jnext = j * chunk; > - dma_addr_t jbase = q->base_paddr + jnext * sizeof(u64); > - > - ixp = &chunk_buffer[inext]; > - *ixp = jbase; > - } > - > - return 0; > -} > - > -static int octeontx_pci_bchvf_probe(struct udevice *dev) > -{ > - struct bch_vf *vf; > - union bch_vqx_ctl ctl; > - union bch_vqx_cmd_buf cbuf; > - int err; > - > - debug("%s(%s)\n", __func__, dev->name); > - vf = dev_get_priv(dev); > - if (!vf) > - return -ENOMEM; > - > - vf->dev = dev; > - > - /* Map PF's configuration registers */ > - vf->reg_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, 0, 0, > - PCI_REGION_TYPE, PCI_REGION_MEM); > - debug("%s: reg base: %p\n", __func__, vf->reg_base); > - > - err = octeontx_cmd_queue_initialize(dev, QID_BCH, QDEPTH - 1, 0, > - sizeof(union bch_cmd) * > QDEPTH); > - if (err) { > - dev_err(dev, "octeontx_cmd_queue_initialize() failed\n"); > - goto release; > - } > - > - ctl.u = readq(vf->reg_base + BCH_VQX_CTL(0)); > - > - cbuf.u = 0; > - cbuf.s.ldwb = 1; > - cbuf.s.dfb = 1; > - cbuf.s.size = QDEPTH; > - writeq(cbuf.u, vf->reg_base + BCH_VQX_CMD_BUF(0)); > - > - writeq(ctl.u, vf->reg_base + BCH_VQX_CTL(0)); > - > - writeq(octeontx_bch_q[QID_BCH].base_paddr, > - vf->reg_base + BCH_VQX_CMD_PTR(0)); > - > - octeontx_bch_putv(vf); > - > - debug("%s: bch vf initialization complete\n", __func__); > - > - if (octeontx_bch_getv()) > - return octeontx_pci_nand_deferred_probe(); > - > - return -1; > - > -release: > - return err; > -} > - > -static int octeontx_pci_bchpf_remove(struct udevice *dev) > -{ > - struct bch_device *bch = dev_get_priv(dev); > - > - bch_disable(bch); > - return 0; > -} > - > -U_BOOT_DRIVER(octeontx_pci_bchpf) = { > - .name = BCHPF_DRIVER_NAME, > - .id = UCLASS_MISC, > - .probe = octeontx_pci_bchpf_probe, > - .remove = octeontx_pci_bchpf_remove, > - .priv_auto = sizeof(struct bch_device), > - .flags = DM_FLAG_OS_PREPARE, > -}; > - > -U_BOOT_DRIVER(octeontx_pci_bchvf) = { > - .name = BCHVF_DRIVER_NAME, > - .id = UCLASS_MISC, > - .probe = octeontx_pci_bchvf_probe, > - .priv_auto = sizeof(struct bch_vf), > -}; > - > -U_BOOT_PCI_DEVICE(octeontx_pci_bchpf, octeontx_bchpf_pci_id_table); > -U_BOOT_PCI_DEVICE(octeontx_pci_bchvf, octeontx_bchvf_pci_id_table); > diff --git a/drivers/mtd/nand/raw/octeontx_bch.h > b/drivers/mtd/nand/raw/octeontx_bch.h > deleted file mode 100644 > index 95a9b7126fbf..000000000000 > --- a/drivers/mtd/nand/raw/octeontx_bch.h > +++ /dev/null > @@ -1,131 +0,0 @@ > -/* SPDX-License-Identifier: GPL-2.0 > - * > - * Copyright (C) 2018 Marvell International Ltd. > - */ > - > -#ifndef __OCTEONTX_BCH_H__ > -#define __OCTEONTX_BCH_H__ > - > -#include "octeontx_bch_regs.h" > - > -/* flags to indicate the features supported */ > -#define BCH_FLAG_SRIOV_ENABLED BIT(1) > - > -/* > - * BCH Registers map for 81xx > - */ > - > -/* PF registers */ > -#define BCH_CTL 0x0ull > -#define BCH_ERR_CFG 0x10ull > -#define BCH_BIST_RESULT 0x80ull > -#define BCH_ERR_INT 0x88ull > -#define BCH_ERR_INT_W1S 0x90ull > -#define BCH_ERR_INT_ENA_W1C 0xA0ull > -#define BCH_ERR_INT_ENA_W1S 0xA8ull > - > -/* VF registers */ > -#define BCH_VQX_CTL(z) 0x0ull > -#define BCH_VQX_CMD_BUF(z) 0x8ull > -#define BCH_VQX_CMD_PTR(z) 0x20ull > -#define BCH_VQX_DOORBELL(z) 0x800ull > - > -#define BCHPF_DRIVER_NAME "octeontx-bchpf" > -#define BCHVF_DRIVER_NAME "octeontx-bchvf" > - > -struct bch_device { > - struct list_head list; > - u8 max_vfs; > - u8 vfs_enabled; > - u8 vfs_in_use; > - u32 flags; > - void __iomem *reg_base; > - struct udevice *dev; > -}; > - > -struct bch_vf { > - u16 flags; > - u8 vfid; > - u8 node; > - u8 priority; > - struct udevice *dev; > - void __iomem *reg_base; > -}; > - > -struct buf_ptr { > - u8 *vptr; > - dma_addr_t dma_addr; > - u16 size; > -}; > - > -void *octeontx_bch_getv(void); > -void octeontx_bch_putv(void *token); > -void *octeontx_bch_getp(void); > -void octeontx_bch_putp(void *token); > -int octeontx_bch_wait(struct bch_vf *vf, union bch_resp *resp, > - dma_addr_t handle); > -/** > - * Given a data block calculate the ecc data and fill in the response > - * > - * @param[in] block 8-byte aligned pointer to data block to calculate > ECC > - * @param block_size Size of block in bytes, must be a multiple of two. > - * @param bch_level Number of errors that must be corrected. The > number of > - * parity bytes is equal to ((15 * bch_level) + 7) / > 8. > - * Must be 4, 8, 16, 24, 32, 40, 48, 56, 60 or 64. > - * @param[out] ecc 8-byte aligned pointer to where ecc data should go > - * @param[in] resp pointer to where responses will be written. > - * > - * Return: Zero on success, negative on failure. > - */ > -int octeontx_bch_encode(struct bch_vf *vf, dma_addr_t block, u16 > block_size, > - u8 bch_level, dma_addr_t ecc, dma_addr_t resp); > - > -/** > - * Given a data block and ecc data correct the data block > - * > - * @param[in] block_ecc_in 8-byte aligned pointer to data block with > ECC > - * data concatenated to the end to correct > - * @param block_size Size of block in bytes, must be a multiple > of > - * two. > - * @param bch_level Number of errors that must be corrected. > The > - * number of parity bytes is equal to > - * ((15 * bch_level) + 7) / 8. > - * Must be 4, 8, 16, 24, 32, 40, 48, 56, 60 > or 64. > - * @param[out] block_out 8-byte aligned pointer to corrected data > buffer. > - * This should not be the same as > block_ecc_in. > - * @param[in] resp pointer to where responses will be written. > - * > - * Return: Zero on success, negative on failure. > - */ > - > -int octeontx_bch_decode(struct bch_vf *vf, dma_addr_t block_ecc_in, > - u16 block_size, u8 bch_level, > - dma_addr_t block_out, dma_addr_t resp); > - > -/** > - * Ring the BCH doorbell telling it that new commands are > - * available. > - * > - * @param num_commands Number of new commands > - * @param vf virtual function handle > - */ > -static inline void octeontx_bch_write_doorbell(u64 num_commands, > - struct bch_vf *vf) > -{ > - u64 num_words = num_commands * sizeof(union bch_cmd) / > sizeof(uint64_t); > - > - writeq(num_words, vf->reg_base + BCH_VQX_DOORBELL(0)); > -} > - > -/** > - * Since it's possible (and even likely) that the NAND device will be > probed > - * before the BCH device has been probed, we may need to defer the > probing. > - * > - * In this case, the initial probe returns success but the actual probing > - * is deferred until the BCH VF has been probed. > - * > - * Return: 0 for success, otherwise error > - */ > -int octeontx_pci_nand_deferred_probe(void); > - > -#endif /* __OCTEONTX_BCH_H__ */ > diff --git a/drivers/mtd/nand/raw/octeontx_bch_regs.h > b/drivers/mtd/nand/raw/octeontx_bch_regs.h > deleted file mode 100644 > index 7d34438fec02..000000000000 > --- a/drivers/mtd/nand/raw/octeontx_bch_regs.h > +++ /dev/null > @@ -1,167 +0,0 @@ > -/* SPDX-License-Identifier: GPL-2.0 > - * > - * Copyright (C) 2018 Marvell International Ltd. > - */ > - > -#ifndef __OCTEONTX_BCH_REGS_H__ > -#define __OCTEONTX_BCH_REGS_H__ > - > -#define BCH_NR_VF 1 > - > -union bch_cmd { > - u64 u[4]; > - struct fields { > - struct { > - u64 size:12; > - u64 reserved_12_31:20; > - u64 ecc_level:4; > - u64 reserved_36_61:26; > - u64 ecc_gen:2; > - } cword; > - struct { > - u64 ptr:49; > - u64 reserved_49_55:7; > - u64 nc:1; > - u64 fw:1; > - u64 reserved_58_63:6; > - } oword; > - struct { > - u64 ptr:49; > - u64 reserved_49_55:7; > - u64 nc:1; > - u64 reserved_57_63:7; > - } iword; > - struct { > - u64 ptr:49; > - u64 reserved_49_63:15; > - } rword; > - } s; > -}; > - > -enum ecc_gen { > - eg_correct, > - eg_copy, > - eg_gen, > - eg_copy3, > -}; > - > -/** Response from BCH instruction */ > -union bch_resp { > - u16 u16; > - struct { > - u16 num_errors:7; /** Number of errors in block */ > - u16 zero:6; /** Always zero, ignore */ > - u16 erased:1; /** Block is erased */ > - u16 uncorrectable:1;/** too many bits flipped */ > - u16 done:1; /** Block is done */ > - } s; > -}; > - > -union bch_vqx_ctl { > - u64 u; > - struct { > - u64 reserved_0:1; > - u64 cmd_be:1; > - u64 max_read:4; > - u64 reserved_6_15:10; > - u64 erase_disable:1; > - u64 one_cmd:1; > - u64 early_term:4; > - u64 reserved_22_63:42; > - } s; > -}; > - > -union bch_vqx_cmd_buf { > - u64 u; > - struct { > - u64 reserved_0_32:33; > - u64 size:13; > - u64 dfb:1; > - u64 ldwb:1; > - u64 reserved_48_63:16; > - } s; > -}; > - > -/* keep queue state indexed, even though just one supported here, > - * for later generalization to similarly-shaped queues on other Cavium > devices > - */ > -enum { > - QID_BCH, > - QID_MAX > -}; > - > -struct bch_q { > - struct udevice *dev; > - int index; > - u16 max_depth; > - u16 pool_size_m1; > - u64 *base_vaddr; > - dma_addr_t base_paddr; > -}; > - > -extern struct bch_q octeontx_bch_q[QID_MAX]; > - > -/* with one dma-mapped area, virt<->phys conversions by +/- (vaddr-paddr) > */ > -static inline dma_addr_t qphys(int qid, void *v) > -{ > - struct bch_q *q = &octeontx_bch_q[qid]; > - int off = (u8 *)v - (u8 *)q->base_vaddr; > - > - return q->base_paddr + off; > -} > - > -#define octeontx_ptr_to_phys(v) qphys(QID_BCH, (v)) > - > -static inline void *qvirt(int qid, dma_addr_t p) > -{ > - struct bch_q *q = &octeontx_bch_q[qid]; > - int off = p - q->base_paddr; > - > - return q->base_vaddr + off; > -} > - > -#define octeontx_phys_to_ptr(p) qvirt(QID_BCH, (p)) > - > -/* plenty for interleaved r/w on two planes with 16k page, ecc_size 1k */ > -/* QDEPTH >= 16, as successive chunks must align on 128-byte boundaries */ > -#define QDEPTH 256 /* u64s in a command queue chunk, incl > next-pointer */ > -#define NQS 1 /* linked chunks in the chain */ > - > -/** > - * Write an arbitrary number of command words to a command queue. > - * This is a generic function; the fixed number of command word > - * functions yield higher performance. > - * > - * Could merge with crypto version for FPA use on cn83xx > - */ > -static inline int octeontx_cmd_queue_write(int queue_id, bool use_locking, > - int cmd_count, const u64 *cmds) > -{ > - int ret = 0; > - u64 *cmd_ptr; > - struct bch_q *qptr = &octeontx_bch_q[queue_id]; > - > - if (unlikely(cmd_count < 1 || cmd_count > 32)) > - return -EINVAL; > - if (unlikely(!cmds)) > - return -EINVAL; > - > - cmd_ptr = qptr->base_vaddr; > - > - while (cmd_count > 0) { > - int slot = qptr->index % (QDEPTH * NQS); > - > - if (slot % QDEPTH != QDEPTH - 1) { > - cmd_ptr[slot] = *cmds++; > - cmd_count--; > - } > - > - qptr->index++; > - } > - > - __iowmb(); /* flush commands before ringing bell */ > - > - return ret; > -} > - > -#endif /* __OCTEONTX_BCH_REGS_H__ */ > diff --git a/drivers/mtd/nand/raw/octeontx_nand.c > b/drivers/mtd/nand/raw/octeontx_nand.c > deleted file mode 100644 > index 3b20685fac03..000000000000 > --- a/drivers/mtd/nand/raw/octeontx_nand.c > +++ /dev/null > @@ -1,2254 +0,0 @@ > -// SPDX-License-Identifier: GPL-2.0 > -/* > - * Copyright (C) 2018 Marvell International Ltd. > - */ > - > -#include <dm.h> > -#include <dm/device-internal.h> > -#include <dm/devres.h> > -#include <dm/of_access.h> > -#include <malloc.h> > -#include <memalign.h> > -#include <nand.h> > -#include <pci.h> > -#include <time.h> > -#include <linux/bitfield.h> > -#include <linux/ctype.h> > -#include <linux/dma-mapping.h> > -#include <linux/delay.h> > -#include <linux/errno.h> > -#include <linux/err.h> > -#include <linux/ioport.h> > -#include <linux/libfdt.h> > -#include <linux/mtd/mtd.h> > -#include <linux/mtd/nand_bch.h> > -#include <linux/mtd/nand_ecc.h> > -#include <linux/mtd/rawnand.h> > -#include <linux/time.h> > -#include <asm/global_data.h> > -#include <asm/io.h> > -#include <asm/types.h> > -#include <asm/dma-mapping.h> > -#include <asm/arch/clock.h> > -#include "octeontx_bch.h" > - > -/* > - * The NDF_CMD queue takes commands between 16 - 128 bit. > - * All commands must be 16 bit aligned and are little endian. > - * WAIT_STATUS commands must be 64 bit aligned. > - * Commands are selected by the 4 bit opcode. > - * > - * Available Commands: > - * > - * 16 Bit: > - * NOP > - * WAIT > - * BUS_ACQ, BUS_REL > - * CHIP_EN, CHIP_DIS > - * > - * 32 Bit: > - * CLE_CMD > - * RD_CMD, RD_EDO_CMD > - * WR_CMD > - * > - * 64 Bit: > - * SET_TM_PAR > - * > - * 96 Bit: > - * ALE_CMD > - * > - * 128 Bit: > - * WAIT_STATUS, WAIT_STATUS_ALE > - */ > - > -/* NDF Register offsets */ > -#define NDF_CMD 0x0 > -#define NDF_MISC 0x8 > -#define NDF_ECC_CNT 0x10 > -#define NDF_DRBELL 0x30 > -#define NDF_ST_REG 0x38 /* status */ > -#define NDF_INT 0x40 > -#define NDF_INT_W1S 0x48 > -#define NDF_DMA_CFG 0x50 > -#define NDF_DMA_ADR 0x58 > -#define NDF_INT_ENA_W1C 0x60 > -#define NDF_INT_ENA_W1S 0x68 > - > -/* NDF command opcodes */ > -#define NDF_OP_NOP 0x0 > -#define NDF_OP_SET_TM_PAR 0x1 > -#define NDF_OP_WAIT 0x2 > -#define NDF_OP_CHIP_EN_DIS 0x3 > -#define NDF_OP_CLE_CMD 0x4 > -#define NDF_OP_ALE_CMD 0x5 > -#define NDF_OP_WR_CMD 0x8 > -#define NDF_OP_RD_CMD 0x9 > -#define NDF_OP_RD_EDO_CMD 0xa > -#define NDF_OP_WAIT_STATUS 0xb /* same opcode for WAIT_STATUS_ALE > */ > -#define NDF_OP_BUS_ACQ_REL 0xf > - > -#define NDF_BUS_ACQUIRE 1 > -#define NDF_BUS_RELEASE 0 > - > -#define DBGX_EDSCR(X) (0x87A008000088 + (X) * 0x80000) > - > -struct ndf_nop_cmd { > - u16 opcode: 4; > - u16 nop: 12; > -}; > - > -struct ndf_wait_cmd { > - u16 opcode:4; > - u16 r_b:1; /* wait for one cycle or PBUS_WAIT > deassert */ > - u16:3; > - u16 wlen:3; /* timing parameter select */ > - u16:5; > -}; > - > -struct ndf_bus_cmd { > - u16 opcode:4; > - u16 direction:4; /* 1 = acquire, 0 = release */ > - u16:8; > -}; > - > -struct ndf_chip_cmd { > - u16 opcode:4; > - u16 chip:3; /* select chip, 0 = disable */ > - u16 enable:1; /* 1 = enable, 0 = disable */ > - u16 bus_width:2; /* 10 = 16 bit, 01 = 8 bit */ > - u16:6; > -}; > - > -struct ndf_cle_cmd { > - u32 opcode:4; > - u32:4; > - u32 cmd_data:8; /* command sent to the PBUS AD pins */ > - u32 clen1:3; /* time between PBUS CLE and WE asserts */ > - u32 clen2:3; /* time WE remains asserted */ > - u32 clen3:3; /* time between WE deassert and CLE */ > - u32:7; > -}; > - > -/* RD_EDO_CMD uses the same layout as RD_CMD */ > -struct ndf_rd_cmd { > - u32 opcode:4; > - u32 data:16; /* data bytes */ > - u32 rlen1:3; > - u32 rlen2:3; > - u32 rlen3:3; > - u32 rlen4:3; > -}; > - > -struct ndf_wr_cmd { > - u32 opcode:4; > - u32 data:16; /* data bytes */ > - u32:4; > - u32 wlen1:3; > - u32 wlen2:3; > - u32:3; > -}; > - > -struct ndf_set_tm_par_cmd { > - u64 opcode:4; > - u64 tim_mult:4; /* multiplier for the seven parameters */ > - u64 tm_par1:8; /* --> Following are the 7 timing parameters that > */ > - u64 tm_par2:8; /* specify the number of coprocessor cycles. > */ > - u64 tm_par3:8; /* A value of zero means one cycle. > */ > - u64 tm_par4:8; /* All values are scaled by tim_mult > */ > - u64 tm_par5:8; /* using tim_par * (2 ^ tim_mult). > */ > - u64 tm_par6:8; > - u64 tm_par7:8; > -}; > - > -struct ndf_ale_cmd { > - u32 opcode:4; > - u32:4; > - u32 adr_byte_num:4; /* number of address bytes to be sent */ > - u32:4; > - u32 alen1:3; > - u32 alen2:3; > - u32 alen3:3; > - u32 alen4:3; > - u32:4; > - u8 adr_byt1; > - u8 adr_byt2; > - u8 adr_byt3; > - u8 adr_byt4; > - u8 adr_byt5; > - u8 adr_byt6; > - u8 adr_byt7; > - u8 adr_byt8; > -}; > - > -struct ndf_wait_status_cmd { > - u32 opcode:4; > - u32:4; > - u32 data:8; /** data */ > - u32 clen1:3; > - u32 clen2:3; > - u32 clen3:3; > - u32:8; > - /** set to 5 to select WAIT_STATUS_ALE command */ > - u32 ale_ind:8; > - /** ALE only: number of address bytes to be sent */ > - u32 adr_byte_num:4; > - u32:4; > - u32 alen1:3; /* ALE only */ > - u32 alen2:3; /* ALE only */ > - u32 alen3:3; /* ALE only */ > - u32 alen4:3; /* ALE only */ > - u32:4; > - u8 adr_byt[4]; /* ALE only */ > - u32 nine:4; /* set to 9 */ > - u32 and_mask:8; > - u32 comp_byte:8; > - u32 rlen1:3; > - u32 rlen2:3; > - u32 rlen3:3; > - u32 rlen4:3; > -}; > - > -union ndf_cmd { > - u64 val[2]; > - union { > - struct ndf_nop_cmd nop; > - struct ndf_wait_cmd wait; > - struct ndf_bus_cmd bus_acq_rel; > - struct ndf_chip_cmd chip_en_dis; > - struct ndf_cle_cmd cle_cmd; > - struct ndf_rd_cmd rd_cmd; > - struct ndf_wr_cmd wr_cmd; > - struct ndf_set_tm_par_cmd set_tm_par; > - struct ndf_ale_cmd ale_cmd; > - struct ndf_wait_status_cmd wait_status; > - } u; > -}; > - > -/** Disable multi-bit error hangs */ > -#define NDF_MISC_MB_DIS BIT_ULL(27) > -/** High watermark for NBR FIFO or load/store operations */ > -#define NDF_MISC_NBR_HWM GENMASK_ULL(26, 24) > -/** Wait input filter count */ > -#define NDF_MISC_WAIT_CNT GENMASK_ULL(23, 18) > -/** Unfilled NFD_CMD queue bytes */ > -#define NDF_MISC_FR_BYTE GENMASK_ULL(17, 7) > -/** Set by HW when it reads the last 8 bytes of NDF_CMD */ > -#define NDF_MISC_RD_DONE BIT_ULL(6) > -/** Set by HW when it reads. SW read of NDF_CMD clears it */ > -#define NDF_MISC_RD_VAL BIT_ULL(5) > -/** Let HW read NDF_CMD queue. Cleared on SW NDF_CMD write */ > -#define NDF_MISC_RD_CMD BIT_ULL(4) > -/** Boot disable */ > -#define NDF_MISC_BT_DIS BIT_ULL(2) > -/** Stop command execution after completing command queue */ > -#define NDF_MISC_EX_DIS BIT_ULL(1) > -/** Reset fifo */ > -#define NDF_MISC_RST_FF BIT_ULL(0) > - > -/** DMA engine enable */ > -#define NDF_DMA_CFG_EN BIT_ULL(63) > -/** Read or write */ > -#define NDF_DMA_CFG_RW BIT_ULL(62) > -/** Terminates DMA and clears enable bit */ > -#define NDF_DMA_CFG_CLR BIT_ULL(61) > -/** 32-bit swap enable */ > -#define NDF_DMA_CFG_SWAP32 BIT_ULL(59) > -/** 16-bit swap enable */ > -#define NDF_DMA_CFG_SWAP16 BIT_ULL(58) > -/** 8-bit swap enable */ > -#define NDF_DMA_CFG_SWAP8 BIT_ULL(57) > -/** Endian mode */ > -#define NDF_DMA_CFG_CMD_BE BIT_ULL(56) > -/** Number of 64 bit transfers */ > -#define NDF_DMA_CFG_SIZE GENMASK_ULL(55, 36) > - > -/** Command execution status idle */ > -#define NDF_ST_REG_EXE_IDLE BIT_ULL(15) > -/** Command execution SM states */ > -#define NDF_ST_REG_EXE_SM GENMASK_ULL(14, 11) > -/** DMA and load SM states */ > -#define NDF_ST_REG_BT_SM GENMASK_ULL(10, 7) > -/** Queue read-back SM bad state */ > -#define NDF_ST_REG_RD_FF_BAD BIT_ULL(6) > -/** Queue read-back SM states */ > -#define NDF_ST_REG_RD_FF GENMASK_ULL(5, 4) > -/** Main SM is in a bad state */ > -#define NDF_ST_REG_MAIN_BAD BIT_ULL(3) > -/** Main SM states */ > -#define NDF_ST_REG_MAIN_SM GENMASK_ULL(2, 0) > - > -#define MAX_NAND_NAME_LEN 64 > -#if (defined(NAND_MAX_PAGESIZE) && (NAND_MAX_PAGESIZE > 4096)) || \ > - !defined(NAND_MAX_PAGESIZE) > -# undef NAND_MAX_PAGESIZE > -# define NAND_MAX_PAGESIZE 4096 > -#endif > -#if (defined(NAND_MAX_OOBSIZE) && (NAND_MAX_OOBSIZE > 256)) || \ > - !defined(NAND_MAX_OOBSIZE) > -# undef NAND_MAX_OOBSIZE > -# define NAND_MAX_OOBSIZE 256 > -#endif > - > -#define OCTEONTX_NAND_DRIVER_NAME "octeontx_nand" > - > -#define NDF_TIMEOUT 1000 /** Timeout in ms */ > -#ifndef NAND_MAX_CHIPS > -# define NAND_MAX_CHIPS 8 /** Linux compatibility */ > -#endif > - > -struct octeontx_nand_chip { > - struct list_head node; > - struct nand_chip nand; > - struct ndf_set_tm_par_cmd timings; > - int cs; > - int selected_page; > - int iface_mode; > - int row_bytes; > - int col_bytes; > - bool oob_only; > - bool iface_set; > -}; > - > -struct octeontx_nand_buf { > - u8 *dmabuf; > - dma_addr_t dmaaddr; > - int dmabuflen; > - int data_len; > - int data_index; > -}; > - > -/** NAND flash controller (NDF) related information */ > -struct octeontx_nfc { > - struct nand_hw_control controller; > - struct udevice *dev; > - void __iomem *base; > - struct list_head chips; > - int selected_chip; /* Currently selected NAND chip number */ > - > - /* > - * Status is separate from octeontx_nand_buf because > - * it can be used in parallel and during init. > - */ > - u8 *stat; > - dma_addr_t stat_addr; > - bool use_status; > - > - struct octeontx_nand_buf buf; > - union bch_resp *bch_resp; > - dma_addr_t bch_rhandle; > - > - /* BCH of all-0xff, so erased pages read as error-free */ > - unsigned char *eccmask; > -}; > - > -/* settable timings - 0..7 select timing of alen1..4/clen1..3/etc */ > -enum tm_idx { > - t0, /* fixed at 4<<mult cycles */ > - t1, t2, t3, t4, t5, t6, t7, /* settable per ONFI-timing mode */ > -}; > - > -struct octeontx_probe_device { > - struct list_head list; > - struct udevice *dev; > -}; > - > -static struct bch_vf *bch_vf; > -/** Deferred devices due to BCH not being ready */ > -static LIST_HEAD(octeontx_pci_nand_deferred_devices); > - > -/** default parameters used for probing chips */ > -#define MAX_ONFI_MODE 5 > - > -static int default_onfi_timing; > -static int slew_ns = 2; /* default timing padding */ > -static int def_ecc_size = 512; /* 1024 best for sw_bch, <= 4095 for > hw_bch */ > -static int default_width = 1; /* 8 bit */ > -static int default_page_size = 2048; > -static struct ndf_set_tm_par_cmd default_timing_parms; > - > -/** Port from Linux */ > -#define readq_poll_timeout(addr, val, cond, delay_us, timeout_us) \ > -({ \ > - ulong __start = get_timer(0); \ > - void *__addr = (addr); \ > - const ulong __timeout_ms = timeout_us / 1000; \ > - do { \ > - (val) = readq(__addr); \ > - if (cond) \ > - break; \ > - if (timeout_us && get_timer(__start) > __timeout_ms) { \ > - (val) = readq(__addr); \ > - break; \ > - } \ > - if (delay_us) \ > - udelay(delay_us); \ > - } while (1); \ > - (cond) ? 0 : -ETIMEDOUT; \ > -}) > - > -/** Ported from Linux 4.9.0 include/linux/of.h for compatibility */ > -static inline int of_get_child_count(const ofnode node) > -{ > - return fdtdec_get_child_count(gd->fdt_blob, > ofnode_to_offset(node)); > -} > - > -/** > - * Linux compatibility from Linux 4.9.0 drivers/mtd/nand/nand_base.c > - */ > -static int nand_ooblayout_ecc_lp(struct mtd_info *mtd, int section, > - struct mtd_oob_region *oobregion) > -{ > - struct nand_chip *chip = mtd_to_nand(mtd); > - struct nand_ecc_ctrl *ecc = &chip->ecc; > - > - if (section || !ecc->total) > - return -ERANGE; > - > - oobregion->length = ecc->total; > - oobregion->offset = mtd->oobsize - oobregion->length; > - > - return 0; > -} > - > -/** > - * Linux compatibility from Linux 4.9.0 drivers/mtd/nand/nand_base.c > - */ > -static int nand_ooblayout_free_lp(struct mtd_info *mtd, int section, > - struct mtd_oob_region *oobregion) > -{ > - struct nand_chip *chip = mtd_to_nand(mtd); > - struct nand_ecc_ctrl *ecc = &chip->ecc; > - > - if (section) > - return -ERANGE; > - > - oobregion->length = mtd->oobsize - ecc->total - 2; > - oobregion->offset = 2; > - > - return 0; > -} > - > -static const struct mtd_ooblayout_ops nand_ooblayout_lp_ops = { > - .ecc = nand_ooblayout_ecc_lp, > - .rfree = nand_ooblayout_free_lp, > -}; > - > -static inline struct octeontx_nand_chip *to_otx_nand(struct nand_chip > *nand) > -{ > - return container_of(nand, struct octeontx_nand_chip, nand); > -} > - > -static inline struct octeontx_nfc *to_otx_nfc(struct nand_hw_control > *ctrl) > -{ > - return container_of(ctrl, struct octeontx_nfc, controller); > -} > - > -static int octeontx_nand_calc_ecc_layout(struct nand_chip *nand) > -{ > - struct nand_ecclayout *layout = nand->ecc.layout; > - struct octeontx_nfc *tn = to_otx_nfc(nand->controller); > - struct mtd_info *mtd = &nand->mtd; > - int oobsize = mtd->oobsize; > - int i; > - bool layout_alloc = false; > - > - if (!layout) { > - layout = devm_kzalloc(tn->dev, sizeof(*layout), > GFP_KERNEL); > - if (!layout) > - return -ENOMEM; > - nand->ecc.layout = layout; > - layout_alloc = true; > - } > - layout->eccbytes = nand->ecc.steps * nand->ecc.bytes; > - /* Reserve 2 bytes for bad block marker */ > - if (layout->eccbytes + 2 > oobsize) { > - pr_err("No suitable oob scheme available for oobsize %d > eccbytes %u\n", > - oobsize, layout->eccbytes); > - goto fail; > - } > - /* put ecc bytes at oob tail */ > - for (i = 0; i < layout->eccbytes; i++) > - layout->eccpos[i] = oobsize - layout->eccbytes + i; > - layout->oobfree[0].offset = 2; > - layout->oobfree[0].length = oobsize - 2 - layout->eccbytes; > - nand->ecc.layout = layout; > - return 0; > - > -fail: > - if (layout_alloc) > - kfree(layout); > - return -1; > -} > - > -/* > - * Read a single byte from the temporary buffer. Used after READID > - * to get the NAND information and for STATUS. > - */ > -static u8 octeontx_nand_read_byte(struct mtd_info *mtd) > -{ > - struct nand_chip *nand = mtd_to_nand(mtd); > - struct octeontx_nfc *tn = to_otx_nfc(nand->controller); > - > - if (tn->use_status) { > - tn->use_status = false; > - return *tn->stat; > - } > - > - if (tn->buf.data_index < tn->buf.data_len) > - return tn->buf.dmabuf[tn->buf.data_index++]; > - > - dev_err(tn->dev, "No data to read, idx: 0x%x, len: 0x%x\n", > - tn->buf.data_index, tn->buf.data_len); > - > - return 0xff; > -} > - > -/* > - * Read a number of pending bytes from the temporary buffer. Used > - * to get page and OOB data. > - */ > -static void octeontx_nand_read_buf(struct mtd_info *mtd, u8 *buf, int len) > -{ > - struct nand_chip *nand = mtd_to_nand(mtd); > - struct octeontx_nfc *tn = to_otx_nfc(nand->controller); > - > - if (len > tn->buf.data_len - tn->buf.data_index) { > - dev_err(tn->dev, "Not enough data for read of %d bytes\n", > len); > - return; > - } > - > - memcpy(buf, tn->buf.dmabuf + tn->buf.data_index, len); > - tn->buf.data_index += len; > -} > - > -static void octeontx_nand_write_buf(struct mtd_info *mtd, > - const u8 *buf, int len) > -{ > - struct nand_chip *nand = mtd_to_nand(mtd); > - struct octeontx_nfc *tn = to_otx_nfc(nand->controller); > - > - memcpy(tn->buf.dmabuf + tn->buf.data_len, buf, len); > - tn->buf.data_len += len; > -} > - > -/* Overwrite default function to avoid sync abort on chip = -1. */ > -static void octeontx_nand_select_chip(struct mtd_info *mtd, int chip) > -{ > -} > - > -static inline int timing_to_cycle(u32 psec, unsigned long clock) > -{ > - unsigned int ns; > - int ticks; > - > - ns = DIV_ROUND_UP(psec, 1000); > - ns += slew_ns; > - > - /* no rounding needed since clock is multiple of 1MHz */ > - clock /= 1000000; > - ns *= clock; > - > - ticks = DIV_ROUND_UP(ns, 1000); > - > - /* actual delay is (tm_parX+1)<<tim_mult */ > - if (ticks) > - ticks--; > - > - return ticks; > -} > - > -static void set_timings(struct octeontx_nand_chip *chip, > - struct ndf_set_tm_par_cmd *tp, > - const struct nand_sdr_timings *timings, > - unsigned long sclk) > -{ > - /* scaled coprocessor-cycle values */ > - u32 s_wh, s_cls, s_clh, s_rp, s_wb, s_wc; > - > - tp->tim_mult = 0; > - s_wh = timing_to_cycle(timings->tWH_min, sclk); > - s_cls = timing_to_cycle(timings->tCLS_min, sclk); > - s_clh = timing_to_cycle(timings->tCLH_min, sclk); > - s_rp = timing_to_cycle(timings->tRP_min, sclk); > - s_wb = timing_to_cycle(timings->tWB_max, sclk); > - s_wc = timing_to_cycle(timings->tWC_min, sclk); > - > - tp->tm_par1 = s_wh; > - tp->tm_par2 = s_clh; > - tp->tm_par3 = s_rp + 1; > - tp->tm_par4 = s_cls - s_wh; > - tp->tm_par5 = s_wc - s_wh + 1; > - tp->tm_par6 = s_wb; > - tp->tm_par7 = 0; > - tp->tim_mult++; /* overcompensate for bad math */ > - > - /* TODO: comment parameter re-use */ > - > - pr_debug("%s: tim_par: mult: %d p1: %d p2: %d p3: %d\n", > - __func__, tp->tim_mult, tp->tm_par1, tp->tm_par2, > tp->tm_par3); > - pr_debug(" p4: %d p5: %d p6: %d p7: %d\n", > - tp->tm_par4, tp->tm_par5, tp->tm_par6, tp->tm_par7); > -} > - > -static int set_default_timings(struct octeontx_nfc *tn, > - const struct nand_sdr_timings *timings) > -{ > - unsigned long sclk = octeontx_get_io_clock(); > - > - set_timings(NULL, &default_timing_parms, timings, sclk); > - return 0; > -} > - > -static int octeontx_nfc_chip_set_timings(struct octeontx_nand_chip *chip, > - const struct nand_sdr_timings > *timings) > -{ > - /*struct octeontx_nfc *tn = to_otx_nfc(chip->nand.controller);*/ > - unsigned long sclk = octeontx_get_io_clock(); > - > - set_timings(chip, &chip->timings, timings, sclk); > - return 0; > -} > - > -/* How many bytes are free in the NFD_CMD queue? */ > -static int ndf_cmd_queue_free(struct octeontx_nfc *tn) > -{ > - u64 ndf_misc; > - > - ndf_misc = readq(tn->base + NDF_MISC); > - return FIELD_GET(NDF_MISC_FR_BYTE, ndf_misc); > -} > - > -/* Submit a command to the NAND command queue. */ > -static int ndf_submit(struct octeontx_nfc *tn, union ndf_cmd *cmd) > -{ > - int opcode = cmd->val[0] & 0xf; > - > - switch (opcode) { > - /* All these commands fit in one 64bit word */ > - case NDF_OP_NOP: > - case NDF_OP_SET_TM_PAR: > - case NDF_OP_WAIT: > - case NDF_OP_CHIP_EN_DIS: > - case NDF_OP_CLE_CMD: > - case NDF_OP_WR_CMD: > - case NDF_OP_RD_CMD: > - case NDF_OP_RD_EDO_CMD: > - case NDF_OP_BUS_ACQ_REL: > - if (ndf_cmd_queue_free(tn) < 8) > - goto full; > - writeq(cmd->val[0], tn->base + NDF_CMD); > - break; > - case NDF_OP_ALE_CMD: > - /* ALE commands take either one or two 64bit words */ > - if (cmd->u.ale_cmd.adr_byte_num < 5) { > - if (ndf_cmd_queue_free(tn) < 8) > - goto full; > - writeq(cmd->val[0], tn->base + NDF_CMD); > - } else { > - if (ndf_cmd_queue_free(tn) < 16) > - goto full; > - writeq(cmd->val[0], tn->base + NDF_CMD); > - writeq(cmd->val[1], tn->base + NDF_CMD); > - } > - break; > - case NDF_OP_WAIT_STATUS: /* Wait status commands take two 64bit > words */ > - if (ndf_cmd_queue_free(tn) < 16) > - goto full; > - writeq(cmd->val[0], tn->base + NDF_CMD); > - writeq(cmd->val[1], tn->base + NDF_CMD); > - break; > - default: > - dev_err(tn->dev, "%s: unknown command: %u\n", __func__, > opcode); > - return -EINVAL; > - } > - return 0; > - > -full: > - dev_err(tn->dev, "%s: no space left in command queue\n", __func__); > - return -ENOMEM; > -} > - > -/** > - * Wait for the ready/busy signal. First wait for busy to be valid, > - * then wait for busy to de-assert. > - */ > -static int ndf_build_wait_busy(struct octeontx_nfc *tn) > -{ > - union ndf_cmd cmd; > - > - memset(&cmd, 0, sizeof(cmd)); > - cmd.u.wait.opcode = NDF_OP_WAIT; > - cmd.u.wait.r_b = 1; > - cmd.u.wait.wlen = t6; > - > - if (ndf_submit(tn, &cmd)) > - return -ENOMEM; > - return 0; > -} > - > -static bool ndf_dma_done(struct octeontx_nfc *tn) > -{ > - u64 dma_cfg; > - > - /* Enable bit should be clear after a transfer */ > - dma_cfg = readq(tn->base + NDF_DMA_CFG); > - if (!(dma_cfg & NDF_DMA_CFG_EN)) > - return true; > - > - return false; > -} > - > -static int ndf_wait(struct octeontx_nfc *tn) > -{ > - ulong start = get_timer(0); > - bool done; > - > - while (!(done = ndf_dma_done(tn)) && get_timer(start) < > NDF_TIMEOUT) > - ; > - > - if (!done) { > - dev_err(tn->dev, "%s: timeout error\n", __func__); > - return -ETIMEDOUT; > - } > - return 0; > -} > - > -static int ndf_wait_idle(struct octeontx_nfc *tn) > -{ > - u64 val; > - u64 dval = 0; > - int rc; > - int pause = 100; > - u64 tot_us = USEC_PER_SEC / 10; > - > - rc = readq_poll_timeout(tn->base + NDF_ST_REG, > - val, val & NDF_ST_REG_EXE_IDLE, pause, > tot_us); > - if (!rc) > - rc = readq_poll_timeout(tn->base + NDF_DMA_CFG, > - dval, !(dval & NDF_DMA_CFG_EN), > - pause, tot_us); > - > - return rc; > -} > - > -/** Issue set timing parameters */ > -static int ndf_queue_cmd_timing(struct octeontx_nfc *tn, > - struct ndf_set_tm_par_cmd *timings) > -{ > - union ndf_cmd cmd; > - > - memset(&cmd, 0, sizeof(cmd)); > - cmd.u.set_tm_par.opcode = NDF_OP_SET_TM_PAR; > - cmd.u.set_tm_par.tim_mult = timings->tim_mult; > - cmd.u.set_tm_par.tm_par1 = timings->tm_par1; > - cmd.u.set_tm_par.tm_par2 = timings->tm_par2; > - cmd.u.set_tm_par.tm_par3 = timings->tm_par3; > - cmd.u.set_tm_par.tm_par4 = timings->tm_par4; > - cmd.u.set_tm_par.tm_par5 = timings->tm_par5; > - cmd.u.set_tm_par.tm_par6 = timings->tm_par6; > - cmd.u.set_tm_par.tm_par7 = timings->tm_par7; > - return ndf_submit(tn, &cmd); > -} > - > -/** Issue bus acquire or release */ > -static int ndf_queue_cmd_bus(struct octeontx_nfc *tn, int direction) > -{ > - union ndf_cmd cmd; > - > - memset(&cmd, 0, sizeof(cmd)); > - cmd.u.bus_acq_rel.opcode = NDF_OP_BUS_ACQ_REL; > - cmd.u.bus_acq_rel.direction = direction; > - return ndf_submit(tn, &cmd); > -} > - > -/* Issue chip select or deselect */ > -static int ndf_queue_cmd_chip(struct octeontx_nfc *tn, int enable, int > chip, > - int width) > -{ > - union ndf_cmd cmd; > - > - memset(&cmd, 0, sizeof(cmd)); > - cmd.u.chip_en_dis.opcode = NDF_OP_CHIP_EN_DIS; > - cmd.u.chip_en_dis.chip = chip; > - cmd.u.chip_en_dis.enable = enable; > - cmd.u.chip_en_dis.bus_width = width; > - return ndf_submit(tn, &cmd); > -} > - > -static int ndf_queue_cmd_wait(struct octeontx_nfc *tn, int t_delay) > -{ > - union ndf_cmd cmd; > - > - memset(&cmd, 0, sizeof(cmd)); > - cmd.u.wait.opcode = NDF_OP_WAIT; > - cmd.u.wait.wlen = t_delay; > - return ndf_submit(tn, &cmd); > -} > - > -static int ndf_queue_cmd_cle(struct octeontx_nfc *tn, int command) > -{ > - union ndf_cmd cmd; > - > - memset(&cmd, 0, sizeof(cmd)); > - cmd.u.cle_cmd.opcode = NDF_OP_CLE_CMD; > - cmd.u.cle_cmd.cmd_data = command; > - cmd.u.cle_cmd.clen1 = t4; > - cmd.u.cle_cmd.clen2 = t1; > - cmd.u.cle_cmd.clen3 = t2; > - return ndf_submit(tn, &cmd); > -} > - > -static int ndf_queue_cmd_ale(struct octeontx_nfc *tn, int addr_bytes, > - struct nand_chip *nand, u64 page, > - u32 col, int page_size) > -{ > - struct octeontx_nand_chip *octeontx_nand = (nand) ? > - to_otx_nand(nand) : NULL; > - union ndf_cmd cmd; > - > - memset(&cmd, 0, sizeof(cmd)); > - cmd.u.ale_cmd.opcode = NDF_OP_ALE_CMD; > - cmd.u.ale_cmd.adr_byte_num = addr_bytes; > - > - /* set column bit for OOB area, assume OOB follows page */ > - if (octeontx_nand && octeontx_nand->oob_only) > - col += page_size; > - > - /* page is u64 for this generality, even if cmdfunc() passes int */ > - switch (addr_bytes) { > - /* 4-8 bytes: page, then 2-byte col */ > - case 8: > - cmd.u.ale_cmd.adr_byt8 = (page >> 40) & 0xff; > - fallthrough; > - case 7: > - cmd.u.ale_cmd.adr_byt7 = (page >> 32) & 0xff; > - fallthrough; > - case 6: > - cmd.u.ale_cmd.adr_byt6 = (page >> 24) & 0xff; > - fallthrough; > - case 5: > - cmd.u.ale_cmd.adr_byt5 = (page >> 16) & 0xff; > - fallthrough; > - case 4: > - cmd.u.ale_cmd.adr_byt4 = (page >> 8) & 0xff; > - cmd.u.ale_cmd.adr_byt3 = page & 0xff; > - cmd.u.ale_cmd.adr_byt2 = (col >> 8) & 0xff; > - cmd.u.ale_cmd.adr_byt1 = col & 0xff; > - break; > - /* 1-3 bytes: just the page address */ > - case 3: > - cmd.u.ale_cmd.adr_byt3 = (page >> 16) & 0xff; > - fallthrough; > - case 2: > - cmd.u.ale_cmd.adr_byt2 = (page >> 8) & 0xff; > - fallthrough; > - case 1: > - cmd.u.ale_cmd.adr_byt1 = page & 0xff; > - break; > - default: > - break; > - } > - > - cmd.u.ale_cmd.alen1 = t3; > - cmd.u.ale_cmd.alen2 = t1; > - cmd.u.ale_cmd.alen3 = t5; > - cmd.u.ale_cmd.alen4 = t2; > - return ndf_submit(tn, &cmd); > -} > - > -static int ndf_queue_cmd_write(struct octeontx_nfc *tn, int len) > -{ > - union ndf_cmd cmd; > - > - memset(&cmd, 0, sizeof(cmd)); > - cmd.u.wr_cmd.opcode = NDF_OP_WR_CMD; > - cmd.u.wr_cmd.data = len; > - cmd.u.wr_cmd.wlen1 = t3; > - cmd.u.wr_cmd.wlen2 = t1; > - return ndf_submit(tn, &cmd); > -} > - > -static int ndf_build_pre_cmd(struct octeontx_nfc *tn, int cmd1, > - int addr_bytes, u64 page, u32 col, int cmd2) > -{ > - struct nand_chip *nand = tn->controller.active; > - struct octeontx_nand_chip *octeontx_nand; > - struct ndf_set_tm_par_cmd *timings; > - int width, page_size, rc; > - > - /* Also called before chip probing is finished */ > - if (!nand) { > - timings = &default_timing_parms; > - page_size = default_page_size; > - width = default_width; > - } else { > - octeontx_nand = to_otx_nand(nand); > - timings = &octeontx_nand->timings; > - page_size = nand->mtd.writesize; > - if (nand->options & NAND_BUSWIDTH_16) > - width = 2; > - else > - width = 1; > - } > - rc = ndf_queue_cmd_timing(tn, timings); > - if (rc) > - return rc; > - > - rc = ndf_queue_cmd_bus(tn, NDF_BUS_ACQUIRE); > - if (rc) > - return rc; > - > - rc = ndf_queue_cmd_chip(tn, 1, tn->selected_chip, width); > - if (rc) > - return rc; > - > - rc = ndf_queue_cmd_wait(tn, t1); > - if (rc) > - return rc; > - > - rc = ndf_queue_cmd_cle(tn, cmd1); > - if (rc) > - return rc; > - > - if (addr_bytes) { > - rc = ndf_build_wait_busy(tn); > - if (rc) > - return rc; > - > - rc = ndf_queue_cmd_ale(tn, addr_bytes, nand, > - page, col, page_size); > - if (rc) > - return rc; > - } > - > - /* CLE 2 */ > - if (cmd2) { > - rc = ndf_build_wait_busy(tn); > - if (rc) > - return rc; > - > - rc = ndf_queue_cmd_cle(tn, cmd2); > - if (rc) > - return rc; > - } > - return 0; > -} > - > -static int ndf_build_post_cmd(struct octeontx_nfc *tn, int hold_time) > -{ > - int rc; > - > - /* Deselect chip */ > - rc = ndf_queue_cmd_chip(tn, 0, 0, 0); > - if (rc) > - return rc; > - > - rc = ndf_queue_cmd_wait(tn, t2); > - if (rc) > - return rc; > - > - /* Release bus */ > - rc = ndf_queue_cmd_bus(tn, 0); > - if (rc) > - return rc; > - > - rc = ndf_queue_cmd_wait(tn, hold_time); > - if (rc) > - return rc; > - > - /* > - * Last action is ringing the doorbell with number of bus > - * acquire-releases cycles (currently 1). > - */ > - writeq(1, tn->base + NDF_DRBELL); > - return 0; > -} > - > -/* Setup the NAND DMA engine for a transfer. */ > -static void ndf_setup_dma(struct octeontx_nfc *tn, int is_write, > - dma_addr_t bus_addr, int len) > -{ > - u64 dma_cfg; > - > - dma_cfg = FIELD_PREP(NDF_DMA_CFG_RW, is_write) | > - FIELD_PREP(NDF_DMA_CFG_SIZE, (len >> 3) - 1); > - dma_cfg |= NDF_DMA_CFG_EN; > - writeq(bus_addr, tn->base + NDF_DMA_ADR); > - writeq(dma_cfg, tn->base + NDF_DMA_CFG); > -} > - > -static int octeontx_nand_reset(struct octeontx_nfc *tn) > -{ > - int rc; > - > - rc = ndf_build_pre_cmd(tn, NAND_CMD_RESET, 0, 0, 0, 0); > - if (rc) > - return rc; > - > - rc = ndf_build_wait_busy(tn); > - if (rc) > - return rc; > - > - rc = ndf_build_post_cmd(tn, t2); > - if (rc) > - return rc; > - > - return 0; > -} > - > -static int ndf_read(struct octeontx_nfc *tn, int cmd1, int addr_bytes, > - u64 page, u32 col, int cmd2, int len) > -{ > - dma_addr_t bus_addr = tn->use_status ? tn->stat_addr : > tn->buf.dmaaddr; > - struct nand_chip *nand = tn->controller.active; > - int timing_mode, bytes, rc; > - union ndf_cmd cmd; > - u64 start, end; > - > - pr_debug("%s(%p, 0x%x, 0x%x, 0x%llx, 0x%x, 0x%x, 0x%x)\n", > __func__, > - tn, cmd1, addr_bytes, page, col, cmd2, len); > - if (!nand) > - timing_mode = default_onfi_timing; > - else > - timing_mode = nand->onfi_timing_mode_default; > - > - /* Build the command and address cycles */ > - rc = ndf_build_pre_cmd(tn, cmd1, addr_bytes, page, col, cmd2); > - if (rc) { > - dev_err(tn->dev, "Build pre command failed\n"); > - return rc; > - } > - > - /* This waits for some time, then waits for busy to be > de-asserted. */ > - rc = ndf_build_wait_busy(tn); > - if (rc) { > - dev_err(tn->dev, "Wait timeout\n"); > - return rc; > - } > - > - memset(&cmd, 0, sizeof(cmd)); > - > - if (timing_mode < 4) > - cmd.u.rd_cmd.opcode = NDF_OP_RD_CMD; > - else > - cmd.u.rd_cmd.opcode = NDF_OP_RD_EDO_CMD; > - > - cmd.u.rd_cmd.data = len; > - cmd.u.rd_cmd.rlen1 = t7; > - cmd.u.rd_cmd.rlen2 = t3; > - cmd.u.rd_cmd.rlen3 = t1; > - cmd.u.rd_cmd.rlen4 = t7; > - rc = ndf_submit(tn, &cmd); > - if (rc) { > - dev_err(tn->dev, "Error submitting command\n"); > - return rc; > - } > - > - start = (u64)bus_addr; > - ndf_setup_dma(tn, 0, bus_addr, len); > - > - rc = ndf_build_post_cmd(tn, t2); > - if (rc) { > - dev_err(tn->dev, "Build post command failed\n"); > - return rc; > - } > - > - /* Wait for the DMA to complete */ > - rc = ndf_wait(tn); > - if (rc) { > - dev_err(tn->dev, "DMA timed out\n"); > - return rc; > - } > - > - end = readq(tn->base + NDF_DMA_ADR); > - bytes = end - start; > - > - /* Make sure NDF is really done */ > - rc = ndf_wait_idle(tn); > - if (rc) { > - dev_err(tn->dev, "poll idle failed\n"); > - return rc; > - } > - > - pr_debug("%s: Read %d bytes\n", __func__, bytes); > - return bytes; > -} > - > -static int octeontx_nand_get_features(struct mtd_info *mtd, > - struct nand_chip *chip, int > feature_addr, > - u8 *subfeature_para) > -{ > - struct nand_chip *nand = chip; > - struct octeontx_nfc *tn = to_otx_nfc(nand->controller); > - int len = 8; > - int rc; > - > - pr_debug("%s: feature addr: 0x%x\n", __func__, feature_addr); > - memset(tn->buf.dmabuf, 0xff, len); > - tn->buf.data_index = 0; > - tn->buf.data_len = 0; > - rc = ndf_read(tn, NAND_CMD_GET_FEATURES, 1, feature_addr, 0, 0, > len); > - if (rc) > - return rc; > - > - memcpy(subfeature_para, tn->buf.dmabuf, ONFI_SUBFEATURE_PARAM_LEN); > - > - return 0; > -} > - > -static int octeontx_nand_set_features(struct mtd_info *mtd, > - struct nand_chip *chip, int > feature_addr, > - u8 *subfeature_para) > -{ > - struct nand_chip *nand = chip; > - struct octeontx_nfc *tn = to_otx_nfc(nand->controller); > - const int len = ONFI_SUBFEATURE_PARAM_LEN; > - int rc; > - > - rc = ndf_build_pre_cmd(tn, NAND_CMD_SET_FEATURES, > - 1, feature_addr, 0, 0); > - if (rc) > - return rc; > - > - memcpy(tn->buf.dmabuf, subfeature_para, len); > - memset(tn->buf.dmabuf + len, 0, 8 - len); > - > - ndf_setup_dma(tn, 1, tn->buf.dmaaddr, 8); > - > - rc = ndf_queue_cmd_write(tn, 8); > - if (rc) > - return rc; > - > - rc = ndf_build_wait_busy(tn); > - if (rc) > - return rc; > - > - rc = ndf_build_post_cmd(tn, t2); > - if (rc) > - return rc; > - > - return 0; > -} > - > -/* > - * Read a page from NAND. If the buffer has room, the out of band > - * data will be included. > - */ > -static int ndf_page_read(struct octeontx_nfc *tn, u64 page, int col, int > len) > -{ > - debug("%s(%p, 0x%llx, 0x%x, 0x%x) active: %p\n", __func__, > - tn, page, col, len, tn->controller.active); > - struct nand_chip *nand = tn->controller.active; > - struct octeontx_nand_chip *chip = to_otx_nand(nand); > - int addr_bytes = chip->row_bytes + chip->col_bytes; > - > - memset(tn->buf.dmabuf, 0xff, len); > - return ndf_read(tn, NAND_CMD_READ0, addr_bytes, > - page, col, NAND_CMD_READSTART, len); > -} > - > -/* Erase a NAND block */ > -static int ndf_block_erase(struct octeontx_nfc *tn, u64 page_addr) > -{ > - struct nand_chip *nand = tn->controller.active; > - struct octeontx_nand_chip *chip = to_otx_nand(nand); > - int addr_bytes = chip->row_bytes; > - int rc; > - > - rc = ndf_build_pre_cmd(tn, NAND_CMD_ERASE1, addr_bytes, > - page_addr, 0, NAND_CMD_ERASE2); > - if (rc) > - return rc; > - > - /* Wait for R_B to signal erase is complete */ > - rc = ndf_build_wait_busy(tn); > - if (rc) > - return rc; > - > - rc = ndf_build_post_cmd(tn, t2); > - if (rc) > - return rc; > - > - /* Wait until the command queue is idle */ > - return ndf_wait_idle(tn); > -} > - > -/* > - * Write a page (or less) to NAND. > - */ > -static int ndf_page_write(struct octeontx_nfc *tn, int page) > -{ > - int len, rc; > - struct nand_chip *nand = tn->controller.active; > - struct octeontx_nand_chip *chip = to_otx_nand(nand); > - int addr_bytes = chip->row_bytes + chip->col_bytes; > - > - len = tn->buf.data_len - tn->buf.data_index; > - chip->oob_only = (tn->buf.data_index >= nand->mtd.writesize); > - WARN_ON_ONCE(len & 0x7); > - > - ndf_setup_dma(tn, 1, tn->buf.dmaaddr + tn->buf.data_index, len); > - rc = ndf_build_pre_cmd(tn, NAND_CMD_SEQIN, addr_bytes, page, 0, 0); > - if (rc) > - return rc; > - > - rc = ndf_queue_cmd_write(tn, len); > - if (rc) > - return rc; > - > - rc = ndf_queue_cmd_cle(tn, NAND_CMD_PAGEPROG); > - if (rc) > - return rc; > - > - /* Wait for R_B to signal program is complete */ > - rc = ndf_build_wait_busy(tn); > - if (rc) > - return rc; > - > - rc = ndf_build_post_cmd(tn, t2); > - if (rc) > - return rc; > - > - /* Wait for the DMA to complete */ > - rc = ndf_wait(tn); > - if (rc) > - return rc; > - > - /* Data transfer is done but NDF is not, it is waiting for R/B# */ > - return ndf_wait_idle(tn); > -} > - > -static void octeontx_nand_cmdfunc(struct mtd_info *mtd, unsigned int > command, > - int column, int page_addr) > -{ > - struct nand_chip *nand = mtd_to_nand(mtd); > - struct octeontx_nand_chip *octeontx_nand = to_otx_nand(nand); > - struct octeontx_nfc *tn = to_otx_nfc(nand->controller); > - int rc; > - > - tn->selected_chip = octeontx_nand->cs; > - if (tn->selected_chip < 0 || tn->selected_chip >= NAND_MAX_CHIPS) { > - dev_err(tn->dev, "invalid chip select\n"); > - return; > - } > - > - tn->use_status = false; > - > - pr_debug("%s(%p, 0x%x, 0x%x, 0x%x) cs: %d\n", __func__, mtd, > command, > - column, page_addr, tn->selected_chip); > - switch (command) { > - case NAND_CMD_READID: > - tn->buf.data_index = 0; > - octeontx_nand->oob_only = false; > - rc = ndf_read(tn, command, 1, column, 0, 0, 8); > - if (rc < 0) > - dev_err(tn->dev, "READID failed with %d\n", rc); > - else > - tn->buf.data_len = rc; > - break; > - > - case NAND_CMD_READOOB: > - octeontx_nand->oob_only = true; > - tn->buf.data_index = 0; > - tn->buf.data_len = 0; > - rc = ndf_page_read(tn, page_addr, column, mtd->oobsize); > - if (rc < mtd->oobsize) > - dev_err(tn->dev, "READOOB failed with %d\n", > - tn->buf.data_len); > - else > - tn->buf.data_len = rc; > - break; > - > - case NAND_CMD_READ0: > - octeontx_nand->oob_only = false; > - tn->buf.data_index = 0; > - tn->buf.data_len = 0; > - rc = ndf_page_read(tn, page_addr, column, > - mtd->writesize + mtd->oobsize); > - > - if (rc < mtd->writesize + mtd->oobsize) > - dev_err(tn->dev, "READ0 failed with %d\n", rc); > - else > - tn->buf.data_len = rc; > - break; > - > - case NAND_CMD_STATUS: > - /* used in oob/not states */ > - tn->use_status = true; > - rc = ndf_read(tn, command, 0, 0, 0, 0, 8); > - if (rc < 0) > - dev_err(tn->dev, "STATUS failed with %d\n", rc); > - break; > - > - case NAND_CMD_RESET: > - /* used in oob/not states */ > - rc = octeontx_nand_reset(tn); > - if (rc < 0) > - dev_err(tn->dev, "RESET failed with %d\n", rc); > - break; > - > - case NAND_CMD_PARAM: > - octeontx_nand->oob_only = false; > - tn->buf.data_index = 0; > - rc = ndf_read(tn, command, 1, 0, 0, 0, > - min(tn->buf.dmabuflen, 3 * 512)); > - if (rc < 0) > - dev_err(tn->dev, "PARAM failed with %d\n", rc); > - else > - tn->buf.data_len = rc; > - break; > - > - case NAND_CMD_RNDOUT: > - tn->buf.data_index = column; > - break; > - > - case NAND_CMD_ERASE1: > - if (ndf_block_erase(tn, page_addr)) > - dev_err(tn->dev, "ERASE1 failed\n"); > - break; > - > - case NAND_CMD_ERASE2: > - /* We do all erase processing in the first command, so > ignore > - * this one. > - */ > - break; > - > - case NAND_CMD_SEQIN: > - octeontx_nand->oob_only = (column >= mtd->writesize); > - tn->buf.data_index = column; > - tn->buf.data_len = column; > - > - octeontx_nand->selected_page = page_addr; > - break; > - > - case NAND_CMD_PAGEPROG: > - rc = ndf_page_write(tn, octeontx_nand->selected_page); > - if (rc) > - dev_err(tn->dev, "PAGEPROG failed with %d\n", rc); > - break; > - > - case NAND_CMD_SET_FEATURES: > - octeontx_nand->oob_only = false; > - /* assume tn->buf.data_len == 4 of data has been set there > */ > - rc = octeontx_nand_set_features(mtd, nand, > - page_addr, tn->buf.dmabuf); > - if (rc) > - dev_err(tn->dev, "SET_FEATURES failed with %d\n", > rc); > - break; > - > - case NAND_CMD_GET_FEATURES: > - octeontx_nand->oob_only = false; > - rc = octeontx_nand_get_features(mtd, nand, > - page_addr, tn->buf.dmabuf); > - if (!rc) { > - tn->buf.data_index = 0; > - tn->buf.data_len = 4; > - } else { > - dev_err(tn->dev, "GET_FEATURES failed with %d\n", > rc); > - } > - break; > - > - default: > - WARN_ON_ONCE(1); > - dev_err(tn->dev, "unhandled nand cmd: %x\n", command); > - } > -} > - > -static int octeontx_nand_waitfunc(struct mtd_info *mtd, struct nand_chip > *chip) > -{ > - struct octeontx_nfc *tn = to_otx_nfc(chip->controller); > - int ret; > - > - ret = ndf_wait_idle(tn); > - return (ret < 0) ? -EIO : 0; > -} > - > -/* check compatibility with ONFI timing mode#N, and optionally apply */ > -/* TODO: Implement chipnr support? */ > -static int octeontx_nand_setup_dat_intf(struct mtd_info *mtd, int chipnr, > - const struct nand_data_interface > *conf) > -{ > - static const bool check_only; > - struct nand_chip *nand = mtd_to_nand(mtd); > - struct octeontx_nand_chip *chip = to_otx_nand(nand); > - static u64 t_wc_n[MAX_ONFI_MODE + 2]; /* cache a mode signature */ > - int mode; /* deduced mode number, for reporting and restricting */ > - int rc; > - > - /* > - * Cache timing modes for reporting, and reducing needless change. > - * > - * Challenge: caller does not pass ONFI mode#, but reporting the > mode > - * and restricting to a maximum, or a list, are useful for > diagnosing > - * new hardware. So use tWC_min, distinct and monotonic across > modes, > - * to discover the requested/accepted mode number > - */ > - for (mode = MAX_ONFI_MODE; mode >= 0 && !t_wc_n[0]; mode--) { > - const struct nand_sdr_timings *t; > - > - t = onfi_async_timing_mode_to_sdr_timings(mode); > - if (!t) > - continue; > - t_wc_n[mode] = t->tWC_min; > - } > - > - if (!conf) { > - rc = -EINVAL; > - } else if (check_only) { > - rc = 0; > - } else if (nand->data_interface && > - chip->iface_set && chip->iface_mode == mode) { > - /* > - * Cases: > - * - called from nand_reset, which clears DDR timing > - * mode back to SDR. BUT if we're already in SDR, > - * timing mode persists over resets. > - * While mtd/nand layer only supports SDR, > - * this is always safe. And this driver only supports > SDR. > - * > - * - called from post-power-event nand_reset (maybe > - * NFC+flash power down, or system hibernate. > - * Address this when CONFIG_PM support added > - */ > - rc = 0; > - } else { > - rc = octeontx_nfc_chip_set_timings(chip, > &conf->timings.sdr); > - if (!rc) { > - chip->iface_mode = mode; > - chip->iface_set = true; > - } > - } > - return rc; > -} > - > -static void octeontx_bch_reset(void) > -{ > -} > - > -/* > - * Given a page, calculate the ECC code > - * > - * chip: Pointer to NAND chip data structure > - * buf: Buffer to calculate ECC on > - * code: Buffer to hold ECC data > - * > - * Return 0 on success or -1 on failure > - */ > -static int octeontx_nand_bch_calculate_ecc_internal(struct mtd_info *mtd, > - dma_addr_t ihandle, > - u8 *code) > -{ > - struct nand_chip *nand = mtd_to_nand(mtd); > - struct octeontx_nfc *tn = to_otx_nfc(nand->controller); > - int rc; > - int i; > - static u8 *ecc_buffer; > - static int ecc_size; > - static unsigned long ecc_handle; > - union bch_resp *r = tn->bch_resp; > - > - if (!ecc_buffer || ecc_size < nand->ecc.size) { > - ecc_size = nand->ecc.size; > - ecc_buffer = dma_alloc_coherent(ecc_size, > - (unsigned long > *)&ecc_handle); > - } > - > - memset(ecc_buffer, 0, nand->ecc.bytes); > - > - r->u16 = 0; > - __iowmb(); /* flush done=0 before making request */ > - > - rc = octeontx_bch_encode(bch_vf, ihandle, nand->ecc.size, > - nand->ecc.strength, > - (dma_addr_t)ecc_handle, tn->bch_rhandle); > - > - if (!rc) { > - octeontx_bch_wait(bch_vf, r, tn->bch_rhandle); > - } else { > - dev_err(tn->dev, "octeontx_bch_encode failed\n"); > - return -1; > - } > - > - if (!r->s.done || r->s.uncorrectable) { > - dev_err(tn->dev, > - "%s timeout, done:%d uncorr:%d corr:%d > erased:%d\n", > - __func__, r->s.done, r->s.uncorrectable, > - r->s.num_errors, r->s.erased); > - octeontx_bch_reset(); > - return -1; > - } > - > - memcpy(code, ecc_buffer, nand->ecc.bytes); > - > - for (i = 0; i < nand->ecc.bytes; i++) > - code[i] ^= tn->eccmask[i]; > - > - return tn->bch_resp->s.num_errors; > -} > - > -/* > - * Given a page, calculate the ECC code > - * > - * mtd: MTD block structure > - * dat: raw data (unused) > - * ecc_code: buffer for ECC > - */ > -static int octeontx_nand_bch_calculate(struct mtd_info *mtd, > - const u8 *dat, u8 *ecc_code) > -{ > - struct nand_chip *nand = mtd_to_nand(mtd); > - dma_addr_t handle = dma_map_single((u8 *)dat, > - nand->ecc.size, DMA_TO_DEVICE); > - int ret; > - > - ret = octeontx_nand_bch_calculate_ecc_internal(mtd, handle, > - (void *)ecc_code); > - > - return ret; > -} > - > -/* > - * Detect and correct multi-bit ECC for a page > - * > - * mtd: MTD block structure > - * dat: raw data read from the chip > - * read_ecc: ECC from the chip (unused) > - * isnull: unused > - * > - * Returns number of bits corrected or -1 if unrecoverable > - */ > -static int octeontx_nand_bch_correct(struct mtd_info *mtd, u_char *dat, > - u_char *read_ecc, u_char *isnull) > -{ > - struct nand_chip *nand = mtd_to_nand(mtd); > - struct octeontx_nfc *tn = to_otx_nfc(nand->controller); > - int i = nand->ecc.size + nand->ecc.bytes; > - static u8 *data_buffer; > - static dma_addr_t ihandle; > - static int buffer_size; > - dma_addr_t ohandle; > - union bch_resp *r = tn->bch_resp; > - int rc; > - > - if (i > buffer_size) { > - if (buffer_size) > - free(data_buffer); > - data_buffer = dma_alloc_coherent(i, > - (unsigned long > *)&ihandle); > - if (!data_buffer) { > - dev_err(tn->dev, > - "%s: Could not allocate %d bytes for > buffer\n", > - __func__, i); > - goto error; > - } > - buffer_size = i; > - } > - > - memcpy(data_buffer, dat, nand->ecc.size); > - memcpy(data_buffer + nand->ecc.size, read_ecc, nand->ecc.bytes); > - > - for (i = 0; i < nand->ecc.bytes; i++) > - data_buffer[nand->ecc.size + i] ^= tn->eccmask[i]; > - > - r->u16 = 0; > - __iowmb(); /* flush done=0 before making request */ > - > - ohandle = dma_map_single(dat, nand->ecc.size, DMA_FROM_DEVICE); > - rc = octeontx_bch_decode(bch_vf, ihandle, nand->ecc.size, > - nand->ecc.strength, ohandle, > tn->bch_rhandle); > - > - if (!rc) > - octeontx_bch_wait(bch_vf, r, tn->bch_rhandle); > - > - if (rc) { > - dev_err(tn->dev, "octeontx_bch_decode failed\n"); > - goto error; > - } > - > - if (!r->s.done) { > - dev_err(tn->dev, "Error: BCH engine timeout\n"); > - octeontx_bch_reset(); > - goto error; > - } > - > - if (r->s.erased) { > - debug("Info: BCH block is erased\n"); > - return 0; > - } > - > - if (r->s.uncorrectable) { > - debug("Cannot correct NAND block, response: 0x%x\n", > - r->u16); > - goto error; > - } > - > - return r->s.num_errors; > - > -error: > - debug("Error performing bch correction\n"); > - return -1; > -} > - > -void octeontx_nand_bch_hwctl(struct mtd_info *mtd, int mode) > -{ > - /* Do nothing. */ > -} > - > -static int octeontx_nand_hw_bch_read_page(struct mtd_info *mtd, > - struct nand_chip *chip, u8 *buf, > - int oob_required, int page) > -{ > - struct nand_chip *nand = mtd_to_nand(mtd); > - struct octeontx_nfc *tn = to_otx_nfc(nand->controller); > - int i, eccsize = chip->ecc.size, ret; > - int eccbytes = chip->ecc.bytes; > - int eccsteps = chip->ecc.steps; > - u8 *p; > - u8 *ecc_code = chip->buffers->ecccode; > - unsigned int max_bitflips = 0; > - > - /* chip->read_buf() insists on sequential order, we do OOB first */ > - memcpy(chip->oob_poi, tn->buf.dmabuf + mtd->writesize, > mtd->oobsize); > - > - /* Use private buffer as input for ECC correction */ > - p = tn->buf.dmabuf; > - > - ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0, > - chip->ecc.total); > - if (ret) > - return ret; > - > - for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { > - int stat; > - > - debug("Correcting block offset %lx, ecc offset %x\n", > - p - buf, i); > - stat = chip->ecc.correct(mtd, p, &ecc_code[i], NULL); > - > - if (stat < 0) { > - mtd->ecc_stats.failed++; > - debug("Cannot correct NAND page %d\n", page); > - } else { > - mtd->ecc_stats.corrected += stat; > - max_bitflips = max_t(unsigned int, max_bitflips, > stat); > - } > - } > - > - /* Copy corrected data to caller's buffer now */ > - memcpy(buf, tn->buf.dmabuf, mtd->writesize); > - > - return max_bitflips; > -} > - > -static int octeontx_nand_hw_bch_write_page(struct mtd_info *mtd, > - struct nand_chip *chip, > - const u8 *buf, int oob_required, > - int page) > -{ > - struct octeontx_nfc *tn = to_otx_nfc(chip->controller); > - int i, eccsize = chip->ecc.size, ret; > - int eccbytes = chip->ecc.bytes; > - int eccsteps = chip->ecc.steps; > - const u8 *p; > - u8 *ecc_calc = chip->buffers->ecccalc; > - > - debug("%s(buf?%p, oob%d p%x)\n", > - __func__, buf, oob_required, page); > - for (i = 0; i < chip->ecc.total; i++) > - ecc_calc[i] = 0xFF; > - > - /* Copy the page data from caller's buffers to private buffer */ > - chip->write_buf(mtd, buf, mtd->writesize); > - /* Use private date as source for ECC calculation */ > - p = tn->buf.dmabuf; > - > - /* Hardware ECC calculation */ > - for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { > - int ret; > - > - ret = chip->ecc.calculate(mtd, p, &ecc_calc[i]); > - > - if (ret < 0) > - debug("calculate(mtd, p?%p, &ecc_calc[%d]?%p) > returned %d\n", > - p, i, &ecc_calc[i], ret); > - > - debug("block offset %lx, ecc offset %x\n", p - buf, i); > - } > - > - ret = mtd_ooblayout_set_eccbytes(mtd, ecc_calc, chip->oob_poi, 0, > - chip->ecc.total); > - if (ret) > - return ret; > - > - /* Store resulting OOB into private buffer, will be sent to HW */ > - chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); > - > - return 0; > -} > - > -/** > - * nand_write_page_raw - [INTERN] raw page write function > - * @mtd: mtd info structure > - * @chip: nand chip info structure > - * @buf: data buffer > - * @oob_required: must write chip->oob_poi to OOB > - * @page: page number to write > - * > - * Not for syndrome calculating ECC controllers, which use a special oob > layout. > - */ > -static int octeontx_nand_write_page_raw(struct mtd_info *mtd, > - struct nand_chip *chip, > - const u8 *buf, int oob_required, > - int page) > -{ > - chip->write_buf(mtd, buf, mtd->writesize); > - if (oob_required) > - chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); > - > - return 0; > -} > - > -/** > - * octeontx_nand_write_oob_std - [REPLACEABLE] the most common OOB data > write > - * function > - * @mtd: mtd info structure > - * @chip: nand chip info structure > - * @page: page number to write > - */ > -static int octeontx_nand_write_oob_std(struct mtd_info *mtd, > - struct nand_chip *chip, > - int page) > -{ > - int status = 0; > - const u8 *buf = chip->oob_poi; > - int length = mtd->oobsize; > - > - chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page); > - chip->write_buf(mtd, buf, length); > - /* Send command to program the OOB data */ > - chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); > - > - status = chip->waitfunc(mtd, chip); > - > - return status & NAND_STATUS_FAIL ? -EIO : 0; > -} > - > -/** > - * octeontx_nand_read_page_raw - [INTERN] read raw page data without ecc > - * @mtd: mtd info structure > - * @chip: nand chip info structure > - * @buf: buffer to store read data > - * @oob_required: caller requires OOB data read to chip->oob_poi > - * @page: page number to read > - * > - * Not for syndrome calculating ECC controllers, which use a special oob > layout. > - */ > -static int octeontx_nand_read_page_raw(struct mtd_info *mtd, > - struct nand_chip *chip, > - u8 *buf, int oob_required, int page) > -{ > - chip->read_buf(mtd, buf, mtd->writesize); > - if (oob_required) > - chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); > - return 0; > -} > - > -static int octeontx_nand_read_oob_std(struct mtd_info *mtd, > - struct nand_chip *chip, > - int page) > - > -{ > - chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); > - chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); > - return 0; > -} > - > -static int octeontx_nand_calc_bch_ecc_strength(struct nand_chip *nand) > -{ > - struct mtd_info *mtd = nand_to_mtd(nand); > - struct nand_ecc_ctrl *ecc = &nand->ecc; > - struct octeontx_nfc *tn = to_otx_nfc(nand->controller); > - int nsteps = mtd->writesize / ecc->size; > - int oobchunk = mtd->oobsize / nsteps; > - > - /* ecc->strength determines ecc_level and OOB's ecc_bytes. */ > - const u8 strengths[] = {4, 8, 16, 24, 32, 40, 48, 56, 60, 64}; > - /* first set the desired ecc_level to match strengths[] */ > - int index = ARRAY_SIZE(strengths) - 1; > - int need; > - > - while (index > 0 && !(ecc->options & NAND_ECC_MAXIMIZE) && > - strengths[index - 1] >= ecc->strength) > - index--; > - > - do { > - need = DIV_ROUND_UP(15 * strengths[index], 8); > - if (need <= oobchunk - 2) > - break; > - } while (index > 0); > - > - debug("%s: steps ds: %d, strength ds: %d\n", __func__, > - nand->ecc_step_ds, nand->ecc_strength_ds); > - ecc->strength = strengths[index]; > - ecc->bytes = need; > - debug("%s: strength: %d, bytes: %d\n", __func__, ecc->strength, > - ecc->bytes); > - > - if (!tn->eccmask) > - tn->eccmask = devm_kzalloc(tn->dev, ecc->bytes, > GFP_KERNEL); > - if (!tn->eccmask) > - return -ENOMEM; > - > - return 0; > -} > - > -/* sample the BCH signature of an erased (all 0xff) page, > - * to XOR into all page traffic, so erased pages have no ECC errors > - */ > -static int octeontx_bch_save_empty_eccmask(struct nand_chip *nand) > -{ > - struct mtd_info *mtd = nand_to_mtd(nand); > - struct octeontx_nfc *tn = to_otx_nfc(nand->controller); > - unsigned int eccsize = nand->ecc.size; > - unsigned int eccbytes = nand->ecc.bytes; > - u8 erased_ecc[eccbytes]; > - unsigned long erased_handle; > - unsigned char *erased_page = dma_alloc_coherent(eccsize, > - &erased_handle); > - int i; > - int rc = 0; > - > - if (!erased_page) > - return -ENOMEM; > - > - memset(erased_page, 0xff, eccsize); > - memset(erased_ecc, 0, eccbytes); > - > - rc = octeontx_nand_bch_calculate_ecc_internal(mtd, > - > (dma_addr_t)erased_handle, > - erased_ecc); > - > - free(erased_page); > - > - for (i = 0; i < eccbytes; i++) > - tn->eccmask[i] = erased_ecc[i] ^ 0xff; > - > - return rc; > -} > - > -static void octeontx_nfc_chip_sizing(struct nand_chip *nand) > -{ > - struct octeontx_nand_chip *chip = to_otx_nand(nand); > - struct mtd_info *mtd = nand_to_mtd(nand); > - struct nand_ecc_ctrl *ecc = &nand->ecc; > - > - chip->row_bytes = nand->onfi_params.addr_cycles & 0xf; > - chip->col_bytes = nand->onfi_params.addr_cycles >> 4; > - debug("%s(%p) row bytes: %d, col bytes: %d, ecc mode: %d\n", > - __func__, nand, chip->row_bytes, chip->col_bytes, ecc->mode); > - > - /* > - * HW_BCH using OcteonTX BCH engine, or SOFT_BCH laid out in > - * HW_BCH-compatible fashion, depending on devtree advice > - * and kernel config. > - * BCH/NFC hardware capable of subpage ops, not implemented. > - */ > - mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops); > - nand->options |= NAND_NO_SUBPAGE_WRITE; > - debug("%s: start steps: %d, size: %d, bytes: %d\n", > - __func__, ecc->steps, ecc->size, ecc->bytes); > - debug("%s: step ds: %d, strength ds: %d\n", __func__, > - nand->ecc_step_ds, nand->ecc_strength_ds); > - > - if (ecc->mode != NAND_ECC_NONE) { > - int nsteps = ecc->steps ? ecc->steps : 1; > - > - if (ecc->size && ecc->size != mtd->writesize) > - nsteps = mtd->writesize / ecc->size; > - else if (mtd->writesize > def_ecc_size && > - !(mtd->writesize & (def_ecc_size - 1))) > - nsteps = mtd->writesize / def_ecc_size; > - ecc->steps = nsteps; > - ecc->size = mtd->writesize / nsteps; > - ecc->bytes = mtd->oobsize / nsteps; > - > - if (nand->ecc_strength_ds) > - ecc->strength = nand->ecc_strength_ds; > - if (nand->ecc_step_ds) > - ecc->size = nand->ecc_step_ds; > - /* > - * no subpage ops, but set subpage-shift to match > ecc->steps > - * so mtd_nandbiterrs tests appropriate boundaries > - */ > - if (!mtd->subpage_sft && !(ecc->steps & (ecc->steps - 1))) > - mtd->subpage_sft = fls(ecc->steps) - 1; > - > - if (IS_ENABLED(CONFIG_NAND_OCTEONTX_HW_ECC)) { > - debug("%s: ecc mode: %d\n", __func__, ecc->mode); > - if (ecc->mode != NAND_ECC_SOFT && > - !octeontx_nand_calc_bch_ecc_strength(nand)) { > - struct octeontx_nfc *tn = > - to_otx_nfc(nand->controller); > - > - debug("Using hardware BCH engine > support\n"); > - ecc->mode = NAND_ECC_HW_SYNDROME; > - ecc->read_page = > octeontx_nand_hw_bch_read_page; > - ecc->write_page = > - octeontx_nand_hw_bch_write_page; > - ecc->read_page_raw = > - octeontx_nand_read_page_raw; > - ecc->write_page_raw = > - octeontx_nand_write_page_raw; > - ecc->read_oob = octeontx_nand_read_oob_std; > - ecc->write_oob = > octeontx_nand_write_oob_std; > - > - ecc->calculate = > octeontx_nand_bch_calculate; > - ecc->correct = octeontx_nand_bch_correct; > - ecc->hwctl = octeontx_nand_bch_hwctl; > - > - debug("NAND chip %d using hw_bch\n", > - tn->selected_chip); > - debug(" %d bytes ECC per %d byte block\n", > - ecc->bytes, ecc->size); > - debug(" for %d bits of correction per > block.", > - ecc->strength); > - octeontx_nand_calc_ecc_layout(nand); > - octeontx_bch_save_empty_eccmask(nand); > - } > - } > - } > -} > - > -static int octeontx_nfc_chip_init(struct octeontx_nfc *tn, struct udevice > *dev, > - ofnode node) > -{ > - struct octeontx_nand_chip *chip; > - struct nand_chip *nand; > - struct mtd_info *mtd; > - int ret; > - > - chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); > - if (!chip) > - return -ENOMEM; > - > - debug("%s: Getting chip select\n", __func__); > - ret = ofnode_read_s32(node, "reg", &chip->cs); > - if (ret) { > - dev_err(dev, "could not retrieve reg property: %d\n", ret); > - return ret; > - } > - > - if (chip->cs >= NAND_MAX_CHIPS) { > - dev_err(dev, "invalid reg value: %u (max CS = 7)\n", > chip->cs); > - return -EINVAL; > - } > - debug("%s: chip select: %d\n", __func__, chip->cs); > - nand = &chip->nand; > - nand->controller = &tn->controller; > - if (!tn->controller.active) > - tn->controller.active = nand; > - > - debug("%s: Setting flash node\n", __func__); > - nand_set_flash_node(nand, node); > - > - nand->options = 0; > - nand->select_chip = octeontx_nand_select_chip; > - nand->cmdfunc = octeontx_nand_cmdfunc; > - nand->waitfunc = octeontx_nand_waitfunc; > - nand->read_byte = octeontx_nand_read_byte; > - nand->read_buf = octeontx_nand_read_buf; > - nand->write_buf = octeontx_nand_write_buf; > - nand->onfi_set_features = octeontx_nand_set_features; > - nand->onfi_get_features = octeontx_nand_get_features; > - nand->setup_data_interface = octeontx_nand_setup_dat_intf; > - > - mtd = nand_to_mtd(nand); > - debug("%s: mtd: %p\n", __func__, mtd); > - mtd->dev->parent = dev; > - > - debug("%s: NDF_MISC: 0x%llx\n", __func__, > - readq(tn->base + NDF_MISC)); > - > - /* TODO: support more then 1 chip */ > - debug("%s: Scanning identification\n", __func__); > - ret = nand_scan_ident(mtd, 1, NULL); > - if (ret) > - return ret; > - > - debug("%s: Sizing chip\n", __func__); > - octeontx_nfc_chip_sizing(nand); > - > - debug("%s: Scanning tail\n", __func__); > - ret = nand_scan_tail(mtd); > - if (ret) { > - dev_err(dev, "nand_scan_tail failed: %d\n", ret); > - return ret; > - } > - > - debug("%s: Registering mtd\n", __func__); > - ret = nand_register(0, mtd); > - > - debug("%s: Adding tail\n", __func__); > - list_add_tail(&chip->node, &tn->chips); > - return 0; > -} > - > -static int octeontx_nfc_chips_init(struct octeontx_nfc *tn) > -{ > - struct udevice *dev = tn->dev; > - ofnode node = dev_ofnode(dev); > - ofnode nand_node; > - int nr_chips = of_get_child_count(node); > - int ret; > - > - debug("%s: node: %s\n", __func__, ofnode_get_name(node)); > - debug("%s: %d chips\n", __func__, nr_chips); > - if (nr_chips > NAND_MAX_CHIPS) { > - dev_err(dev, "too many NAND chips: %d\n", nr_chips); > - return -EINVAL; > - } > - > - if (!nr_chips) { > - debug("no DT NAND chips found\n"); > - return -ENODEV; > - } > - > - pr_info("%s: scanning %d chips DTs\n", __func__, nr_chips); > - > - ofnode_for_each_subnode(nand_node, node) { > - debug("%s: Calling octeontx_nfc_chip_init(%p, %s, %ld)\n", > - __func__, tn, dev->name, nand_node.of_offset); > - ret = octeontx_nfc_chip_init(tn, dev, nand_node); > - if (ret) > - return ret; > - } > - return 0; > -} > - > -/* Reset NFC and initialize registers. */ > -static int octeontx_nfc_init(struct octeontx_nfc *tn) > -{ > - const struct nand_sdr_timings *timings; > - u64 ndf_misc; > - int rc; > - > - /* Initialize values and reset the fifo */ > - ndf_misc = readq(tn->base + NDF_MISC); > - > - ndf_misc &= ~NDF_MISC_EX_DIS; > - ndf_misc |= (NDF_MISC_BT_DIS | NDF_MISC_RST_FF); > - writeq(ndf_misc, tn->base + NDF_MISC); > - debug("%s: NDF_MISC: 0x%llx\n", __func__, readq(tn->base + > NDF_MISC)); > - > - /* Bring the fifo out of reset */ > - ndf_misc &= ~(NDF_MISC_RST_FF); > - > - /* Maximum of co-processor cycles for glitch filtering */ > - ndf_misc |= FIELD_PREP(NDF_MISC_WAIT_CNT, 0x3f); > - > - writeq(ndf_misc, tn->base + NDF_MISC); > - > - /* Set timing parameters to onfi mode 0 for probing */ > - timings = onfi_async_timing_mode_to_sdr_timings(0); > - if (IS_ERR(timings)) > - return PTR_ERR(timings); > - rc = set_default_timings(tn, timings); > - if (rc) > - return rc; > - > - return 0; > -} > - > -static int octeontx_pci_nand_probe(struct udevice *dev) > -{ > - struct octeontx_nfc *tn = dev_get_priv(dev); > - int ret; > - static bool probe_done; > - > - debug("%s(%s) tn: %p\n", __func__, dev->name, tn); > - if (probe_done) > - return 0; > - > - if (IS_ENABLED(CONFIG_NAND_OCTEONTX_HW_ECC)) { > - bch_vf = octeontx_bch_getv(); > - if (!bch_vf) { > - struct octeontx_probe_device *probe_dev; > - > - debug("%s: bch not yet initialized\n", __func__); > - probe_dev = calloc(sizeof(*probe_dev), 1); > - if (!probe_dev) { > - printf("%s: Out of memory\n", __func__); > - return -ENOMEM; > - } > - probe_dev->dev = dev; > - INIT_LIST_HEAD(&probe_dev->list); > - list_add_tail(&probe_dev->list, > - &octeontx_pci_nand_deferred_devices); > - debug("%s: Defering probe until after BCH > initialization\n", > - __func__); > - return 0; > - } > - } > - > - tn->dev = dev; > - INIT_LIST_HEAD(&tn->chips); > - > - tn->base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, 0, 0, > PCI_REGION_TYPE, PCI_REGION_MEM); > - if (!tn->base) { > - ret = -EINVAL; > - goto release; > - } > - debug("%s: bar at %p\n", __func__, tn->base); > - tn->buf.dmabuflen = NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE; > - tn->buf.dmabuf = dma_alloc_coherent(tn->buf.dmabuflen, > - (unsigned long > *)&tn->buf.dmaaddr); > - if (!tn->buf.dmabuf) { > - ret = -ENOMEM; > - debug("%s: Could not allocate DMA buffer\n", __func__); > - goto unclk; > - } > - > - /* one hw-bch response, for one outstanding transaction */ > - tn->bch_resp = dma_alloc_coherent(sizeof(*tn->bch_resp), > - (unsigned long > *)&tn->bch_rhandle); > - > - tn->stat = dma_alloc_coherent(8, (unsigned long *)&tn->stat_addr); > - if (!tn->stat || !tn->bch_resp) { > - debug("%s: Could not allocate bch status or response\n", > - __func__); > - ret = -ENOMEM; > - goto unclk; > - } > - > - debug("%s: Calling octeontx_nfc_init()\n", __func__); > - octeontx_nfc_init(tn); > - debug("%s: Initializing chips\n", __func__); > - ret = octeontx_nfc_chips_init(tn); > - debug("%s: init chips ret: %d\n", __func__, ret); > - if (ret) { > - if (ret != -ENODEV) > - dev_err(dev, "failed to init nand chips\n"); > - goto unclk; > - } > - dev_info(dev, "probed\n"); > - return 0; > - > -unclk: > -release: > - return ret; > -} > - > -int octeontx_pci_nand_disable(struct udevice *dev) > -{ > - struct octeontx_nfc *tn = dev_get_priv(dev); > - u64 dma_cfg; > - u64 ndf_misc; > - > - debug("%s: Disabling NAND device %s\n", __func__, dev->name); > - dma_cfg = readq(tn->base + NDF_DMA_CFG); > - dma_cfg &= ~NDF_DMA_CFG_EN; > - dma_cfg |= NDF_DMA_CFG_CLR; > - writeq(dma_cfg, tn->base + NDF_DMA_CFG); > - > - /* Disable execution and put FIFO in reset mode */ > - ndf_misc = readq(tn->base + NDF_MISC); > - ndf_misc |= NDF_MISC_EX_DIS | NDF_MISC_RST_FF; > - writeq(ndf_misc, tn->base + NDF_MISC); > - ndf_misc &= ~NDF_MISC_RST_FF; > - writeq(ndf_misc, tn->base + NDF_MISC); > -#ifdef DEBUG > - printf("%s: NDF_MISC: 0x%llx\n", __func__, readq(tn->base + > NDF_MISC)); > -#endif > - /* Clear any interrupts and enable bits */ > - writeq(~0ull, tn->base + NDF_INT_ENA_W1C); > - writeq(~0ull, tn->base + NDF_INT); > - debug("%s: NDF_ST_REG: 0x%llx\n", __func__, > - readq(tn->base + NDF_ST_REG)); > - return 0; > -} > - > -/** > - * Since it's possible (and even likely) that the NAND device will be > probed > - * before the BCH device has been probed, we may need to defer the > probing. > - * > - * In this case, the initial probe returns success but the actual probing > - * is deferred until the BCH VF has been probed. > - * > - * Return: 0 for success, otherwise error > - */ > -int octeontx_pci_nand_deferred_probe(void) > -{ > - int rc = 0; > - struct octeontx_probe_device *pdev; > - > - debug("%s: Performing deferred probing\n", __func__); > - list_for_each_entry(pdev, &octeontx_pci_nand_deferred_devices, > list) { > - debug("%s: Probing %s\n", __func__, pdev->dev->name); > - dev_get_flags(pdev->dev) &= ~DM_FLAG_ACTIVATED; > - rc = device_probe(pdev->dev); > - if (rc && rc != -ENODEV) { > - printf("%s: Error %d with deferred probe of %s\n", > - __func__, rc, pdev->dev->name); > - break; > - } > - } > - return rc; > -} > - > -static const struct pci_device_id octeontx_nfc_pci_id_table[] = { > - { PCI_VDEVICE(CAVIUM, 0xA04F) }, > - {} > -}; > - > -static int octeontx_nand_of_to_plat(struct udevice *dev) > -{ > - return 0; > -} > - > -static const struct udevice_id octeontx_nand_ids[] = { > - { .compatible = "cavium,cn8130-nand" }, > - { }, > -}; > - > -U_BOOT_DRIVER(octeontx_pci_nand) = { > - .name = OCTEONTX_NAND_DRIVER_NAME, > - .id = UCLASS_MTD, > - .of_match = of_match_ptr(octeontx_nand_ids), > - .of_to_plat = octeontx_nand_of_to_plat, > - .probe = octeontx_pci_nand_probe, > - .priv_auto = sizeof(struct octeontx_nfc), > - .remove = octeontx_pci_nand_disable, > - .flags = DM_FLAG_OS_PREPARE, > -}; > - > -U_BOOT_PCI_DEVICE(octeontx_pci_nand, octeontx_nfc_pci_id_table); > - > -void board_nand_init(void) > -{ > - struct udevice *dev; > - int ret; > - > - if (IS_ENABLED(CONFIG_NAND_OCTEONTX_HW_ECC)) { > - ret = uclass_get_device_by_driver(UCLASS_MISC, > - > DM_DRIVER_GET(octeontx_pci_bchpf), > - &dev); > - if (ret && ret != -ENODEV) { > - pr_err("Failed to initialize OcteonTX BCH PF > controller. (error %d)\n", > - ret); > - } > - ret = uclass_get_device_by_driver(UCLASS_MISC, > - > DM_DRIVER_GET(octeontx_pci_bchvf), > - &dev); > - if (ret && ret != -ENODEV) { > - pr_err("Failed to initialize OcteonTX BCH VF > controller. (error %d)\n", > - ret); > - } > - } > - > - ret = uclass_get_device_by_driver(UCLASS_MTD, > - DM_DRIVER_GET(octeontx_pci_nand), > - &dev); > - if (ret && ret != -ENODEV) > - pr_err("Failed to initialize OcteonTX NAND controller. > (error %d)\n", > - ret); > -} > -- > 2.43.0 > > -- Michael Nazzareno Trimarchi Co-Founder & Chief Executive Officer M. +39 347 913 2170 mich...@amarulasolutions.com __________________________________ Amarula Solutions BV Joop Geesinkweg 125, 1114 AB, Amsterdam, NL T. +31 (0)85 111 9172 i...@amarulasolutions.com www.amarulasolutions.com