From 42ef9a0b7f26ccd7b657e9686a406ee83b8bd08d Mon Sep 17 00:00:00 2001 From: Andrew Goodbody Date: Fri, 1 Aug 2025 11:39:13 +0100 Subject: [PATCH 1/9] mtd: nand: pxa3xx: Free memory on error In pxa3xx_nand_probe_dt if the function detects an error after allocating memory that memory is not freed before exit. Add the appropriate free. This issue was found by Smatch. Signed-off-by: Andrew Goodbody Reviewed-by: MIchael Trimarchi --- drivers/mtd/nand/raw/pxa3xx_nand.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mtd/nand/raw/pxa3xx_nand.c b/drivers/mtd/nand/raw/pxa3xx_nand.c index b78b4e60238..7bf54fa4654 100644 --- a/drivers/mtd/nand/raw/pxa3xx_nand.c +++ b/drivers/mtd/nand/raw/pxa3xx_nand.c @@ -1765,6 +1765,7 @@ static int pxa3xx_nand_probe_dt(struct udevice *dev, struct pxa3xx_nand_info *in pdata->num_cs = dev_read_u32_default(dev, "num-cs", 1); if (pdata->num_cs != 1) { pr_err("pxa3xx driver supports single CS only\n"); + kfree(pdata); return -EINVAL; } From 4003ed1c1ecfc88092a1d3c65bf432ab7c2ea15f Mon Sep 17 00:00:00 2001 From: Andrew Goodbody Date: Fri, 1 Aug 2025 11:39:14 +0100 Subject: [PATCH 2/9] mtd: rawnand: stm32_fmc2: Ensure to return error code In stm32_fmc2_nfc_probe there are 3 error returns that do not set the error code before returning which could lead to the error being silently ignored. Just return -EINVAL in each case. This issue was found by Smatch. Signed-off-by: Andrew Goodbody Reviewed-by: Patrice Chotard --- drivers/mtd/nand/raw/stm32_fmc2_nand.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/mtd/nand/raw/stm32_fmc2_nand.c b/drivers/mtd/nand/raw/stm32_fmc2_nand.c index 083ea4c5a74..d1c88643c98 100644 --- a/drivers/mtd/nand/raw/stm32_fmc2_nand.c +++ b/drivers/mtd/nand/raw/stm32_fmc2_nand.c @@ -942,21 +942,21 @@ static int stm32_fmc2_nfc_probe(struct udevice *dev) addr = dev_read_addr_index(dev, mem_region); if (addr == FDT_ADDR_T_NONE) { dev_err(dev, "Resource data_base not found for cs%d", chip_cs); - return ret; + return -EINVAL; } nfc->data_base[chip_cs] = addr; addr = dev_read_addr_index(dev, mem_region + 1); if (addr == FDT_ADDR_T_NONE) { dev_err(dev, "Resource cmd_base not found for cs%d", chip_cs); - return ret; + return -EINVAL; } nfc->cmd_base[chip_cs] = addr; addr = dev_read_addr_index(dev, mem_region + 2); if (addr == FDT_ADDR_T_NONE) { dev_err(dev, "Resource addr_base not found for cs%d", chip_cs); - return ret; + return -EINVAL; } nfc->addr_base[chip_cs] = addr; } From 56372f834c717402882112ba888943421020b6d5 Mon Sep 17 00:00:00 2001 From: Andrew Goodbody Date: Fri, 1 Aug 2025 11:39:15 +0100 Subject: [PATCH 3/9] mtd: nand: sunxi: Free allocated memory on errors Add kfree calls on error paths for memory that was allocated. This will prevent memory leaks. This issue found by Smatch. Signed-off-by: Andrew Goodbody Reviewed-By: Michael Trimarchi --- drivers/mtd/nand/raw/sunxi_nand.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/nand/raw/sunxi_nand.c b/drivers/mtd/nand/raw/sunxi_nand.c index 34197bb09a1..1ce09b56b80 100644 --- a/drivers/mtd/nand/raw/sunxi_nand.c +++ b/drivers/mtd/nand/raw/sunxi_nand.c @@ -1403,8 +1403,10 @@ static int sunxi_nand_hw_common_ecc_ctrl_init(struct mtd_info *mtd, if (!data) return -ENOMEM; - if (ecc->size != 512 && ecc->size != 1024) + if (ecc->size != 512 && ecc->size != 1024) { + kfree(data); return -EINVAL; + } /* Prefer 1k ECC chunk over 512 ones */ if (ecc->size == 512 && mtd->writesize > 512) { @@ -1641,17 +1643,20 @@ static int sunxi_nand_chip_init(struct udevice *dev, struct sunxi_nfc *nfc, if (ret) { dev_err(dev, "could not retrieve reg property: %d\n", ret); + kfree(chip); return ret; } if (tmp > NFC_MAX_CS) { dev_err(dev, "invalid reg value: %u (max CS = 7)\n", tmp); + kfree(chip); return -EINVAL; } if (test_and_set_bit(tmp, &nfc->assigned_cs)) { dev_err(dev, "CS %d already assigned\n", tmp); + kfree(chip); return -EINVAL; } @@ -1678,12 +1683,14 @@ static int sunxi_nand_chip_init(struct udevice *dev, struct sunxi_nfc *nfc, dev_err(dev, "could not retrieve timings for ONFI mode 0: %d\n", ret); + kfree(chip); return ret; } ret = sunxi_nand_chip_set_timings(nfc, chip, timings); if (ret) { dev_err(dev, "could not configure chip timings: %d\n", ret); + kfree(chip); return ret; } @@ -1705,8 +1712,10 @@ static int sunxi_nand_chip_init(struct udevice *dev, struct sunxi_nfc *nfc, mtd = nand_to_mtd(nand); ret = nand_scan_ident(mtd, nsels, NULL); - if (ret) + if (ret) { + kfree(chip); return ret; + } if (nand->bbt_options & NAND_BBT_USE_FLASH) nand->bbt_options |= NAND_BBT_NO_OOB; @@ -1719,24 +1728,28 @@ static int sunxi_nand_chip_init(struct udevice *dev, struct sunxi_nfc *nfc, ret = sunxi_nand_chip_init_timings(nfc, chip); if (ret) { dev_err(dev, "could not configure chip timings: %d\n", ret); + kfree(chip); return ret; } ret = sunxi_nand_ecc_init(mtd, &nand->ecc); if (ret) { dev_err(dev, "ECC init failed: %d\n", ret); + kfree(chip); return ret; } ret = nand_scan_tail(mtd); if (ret) { dev_err(dev, "nand_scan_tail failed: %d\n", ret); + kfree(chip); return ret; } ret = nand_register(devnum, mtd); if (ret) { dev_err(dev, "failed to register mtd device: %d\n", ret); + kfree(chip); return ret; } From ebf8aaf7afdeb306b0fb85be2226a00aef18162f Mon Sep 17 00:00:00 2001 From: Andrew Goodbody Date: Fri, 1 Aug 2025 10:54:04 +0100 Subject: [PATCH 4/9] mtd: rawnand: cortina_nand: Fix -ENOMEM detection In init_nand_dma there was code to detect failure to allocate memory but it had two problems. Firstly the 2nd clause when info->tx_desc was NULL attempted to free info->tx_desc when it should be freeing info->rx_desc. Secondly there was no detection of both allocations failing, arguably the more likely scenario. Refactor the code to simplify it and just fail as soon as either allocation fails. This issue was found by Smatch. Signed-off-by: Andrew Goodbody Reviewed-by: Michael Trimarchi --- drivers/mtd/nand/raw/cortina_nand.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/mtd/nand/raw/cortina_nand.c b/drivers/mtd/nand/raw/cortina_nand.c index 06918a46e93..a27a6994f56 100644 --- a/drivers/mtd/nand/raw/cortina_nand.c +++ b/drivers/mtd/nand/raw/cortina_nand.c @@ -186,14 +186,13 @@ int init_nand_dma(struct nand_chip *nand) info->tx_desc = malloc_cache_aligned((sizeof(struct tx_descriptor_t) * CA_DMA_DESC_NUM)); + if (!info->tx_desc) { + printf("Fail to alloc DMA descript!\n"); + return -ENOMEM; + } info->rx_desc = malloc_cache_aligned((sizeof(struct rx_descriptor_t) * CA_DMA_DESC_NUM)); - - if (!info->rx_desc && info->tx_desc) { - printf("Fail to alloc DMA descript!\n"); - kfree(info->tx_desc); - return -ENOMEM; - } else if (info->rx_desc && !info->tx_desc) { + if (!info->rx_desc) { printf("Fail to alloc DMA descript!\n"); kfree(info->tx_desc); return -ENOMEM; From 2756de5213a1a88fae236d7be217c882b5daef9f Mon Sep 17 00:00:00 2001 From: Andrew Goodbody Date: Fri, 1 Aug 2025 10:54:05 +0100 Subject: [PATCH 5/9] mtd: rawnand: denali: Remove always true test In denali_wait_for_irq the code will either return from inside the while loop or exit with time_left being 0. The following test for time_left being 0 is guranteed to be true so remove the test and the following unreachable code. This issue was found by Smatch. Signed-off-by: Andrew Goodbody Reviewed-by: Michael Trimarchi --- drivers/mtd/nand/raw/denali.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/mtd/nand/raw/denali.c b/drivers/mtd/nand/raw/denali.c index b2401116689..39cb641e0b3 100644 --- a/drivers/mtd/nand/raw/denali.c +++ b/drivers/mtd/nand/raw/denali.c @@ -173,13 +173,9 @@ static uint32_t denali_wait_for_irq(struct denali_nand_info *denali, time_left--; } - if (!time_left) { - dev_err(denali->dev, "timeout while waiting for irq 0x%x\n", - irq_mask); - return 0; - } - - return denali->irq_status; + dev_err(denali->dev, "timeout while waiting for irq 0x%x\n", + irq_mask); + return 0; } static uint32_t denali_check_irq(struct denali_nand_info *denali) From 27242462167f678cb6ec78fa8c97f25c9557cb1e Mon Sep 17 00:00:00 2001 From: Andrew Goodbody Date: Fri, 1 Aug 2025 10:54:06 +0100 Subject: [PATCH 6/9] mtd: rawnand: mxs_nand: Ensure err is set for error path In mxs_nand_init_ctrl there are a couple of error paths that do not set err which could lead to the errors being silently ignored despite the function not completing. Rather than just using if to detect these errors use err to collect the error return value from the called functions. This issue was found by Smatch. Signed-off-by: Andrew Goodbody Reviewed-by: Michael Trimarchi --- drivers/mtd/nand/raw/mxs_nand.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/nand/raw/mxs_nand.c b/drivers/mtd/nand/raw/mxs_nand.c index ba67466069b..fecf1f5ba91 100644 --- a/drivers/mtd/nand/raw/mxs_nand.c +++ b/drivers/mtd/nand/raw/mxs_nand.c @@ -1640,10 +1640,12 @@ int mxs_nand_init_ctrl(struct mxs_nand_info *nand_info) nand->setup_data_interface = mxs_nand_setup_interface; /* first scan to find the device and get the page size */ - if (nand_scan_ident(mtd, CONFIG_SYS_MAX_NAND_DEVICE, NULL)) + err = nand_scan_ident(mtd, CONFIG_SYS_MAX_NAND_DEVICE, NULL); + if (err) goto err_free_buffers; - if (mxs_nand_setup_ecc(mtd)) + err = mxs_nand_setup_ecc(mtd); + if (err) goto err_free_buffers; nand->ecc.read_page = mxs_nand_ecc_read_page; From 2412f00fc95c73d1683ee385d464c9d4cea8c34a Mon Sep 17 00:00:00 2001 From: Tom Rini Date: Sun, 3 Aug 2025 10:27:47 +0200 Subject: [PATCH 7/9] mtd: nand: raw: Remove unused lpc32xx_nand_slc driver As no platforms use this driver anymore let's go ahead and remove it. Signed-off-by: Tom Rini --- arch/arm/include/asm/arch-lpc32xx/config.h | 19 - drivers/mtd/nand/raw/Kconfig | 9 +- drivers/mtd/nand/raw/Makefile | 1 - drivers/mtd/nand/raw/lpc32xx_nand_slc.c | 587 --------------------- 4 files changed, 2 insertions(+), 614 deletions(-) delete mode 100644 drivers/mtd/nand/raw/lpc32xx_nand_slc.c diff --git a/arch/arm/include/asm/arch-lpc32xx/config.h b/arch/arm/include/asm/arch-lpc32xx/config.h index b2d87524f70..e4005b94b54 100644 --- a/arch/arm/include/asm/arch-lpc32xx/config.h +++ b/arch/arm/include/asm/arch-lpc32xx/config.h @@ -17,25 +17,6 @@ #define CFG_SYS_BAUDRATE_TABLE \ { 9600, 19200, 38400, 57600, 115200, 230400, 460800 } -/* NAND */ -#if defined(CONFIG_NAND_LPC32XX_SLC) -#define NAND_LARGE_BLOCK_PAGE_SIZE 0x800 -#define NAND_SMALL_BLOCK_PAGE_SIZE 0x200 - -#if (CONFIG_SYS_NAND_PAGE_SIZE == NAND_LARGE_BLOCK_PAGE_SIZE) -#define CFG_SYS_NAND_ECCPOS { 40, 41, 42, 43, 44, 45, 46, 47, \ - 48, 49, 50, 51, 52, 53, 54, 55, \ - 56, 57, 58, 59, 60, 61, 62, 63, } -#elif (CONFIG_SYS_NAND_PAGE_SIZE == NAND_SMALL_BLOCK_PAGE_SIZE) -#define CFG_SYS_NAND_ECCPOS { 10, 11, 12, 13, 14, 15, } -#else -#error "CONFIG_SYS_NAND_PAGE_SIZE set to an invalid value" -#endif - -#define CFG_SYS_NAND_ECCSIZE 0x100 -#define CFG_SYS_NAND_ECCBYTES 3 -#endif /* CONFIG_NAND_LPC32XX_SLC */ - /* NOR Flash */ /* USB OHCI */ diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig index adb271dfb8f..2099825f4cf 100644 --- a/drivers/mtd/nand/raw/Kconfig +++ b/drivers/mtd/nand/raw/Kconfig @@ -261,11 +261,6 @@ config NAND_LPC32XX_MLC help Enable the LPC32XX MLC NAND controller. -config NAND_LPC32XX_SLC - bool "Support LPC32XX_SLC controller" - help - Enable the LPC32XX SLC NAND controller. - config NAND_OMAP_GPMC bool "Support OMAP GPMC NAND controller" depends on ARCH_OMAP2PLUS || ARCH_KEYSTONE || ARCH_K3 @@ -684,7 +679,7 @@ config SYS_NAND_ONFI_DETECTION config SYS_NAND_PAGE_SIZE hex "NAND chip page size" - depends on ARCH_SUNXI || NAND_OMAP_GPMC || NAND_LPC32XX_SLC || \ + depends on ARCH_SUNXI || NAND_OMAP_GPMC || \ SPL_NAND_SIMPLE || (NAND_MXC && SPL_NAND_SUPPORT) || \ MVEBU_SPL_BOOT_DEVICE_NAND || \ (NAND_ATMEL && SPL_NAND_SUPPORT) || \ @@ -696,7 +691,7 @@ config SYS_NAND_PAGE_SIZE config SYS_NAND_OOBSIZE hex "NAND chip OOB size" - depends on ARCH_SUNXI || NAND_OMAP_GPMC || NAND_LPC32XX_SLC || \ + depends on ARCH_SUNXI || NAND_OMAP_GPMC || \ SPL_NAND_SIMPLE || (NAND_MXC && SPL_NAND_SUPPORT) || \ (NAND_ATMEL && SPL_NAND_SUPPORT) || SPL_GENERATE_ATMEL_PMECC_HEADER depends on !NAND_MXS && !NAND_DENALI_DT && !NAND_LPC32XX_MLC diff --git a/drivers/mtd/nand/raw/Makefile b/drivers/mtd/nand/raw/Makefile index 34cba77046a..97e874ef769 100644 --- a/drivers/mtd/nand/raw/Makefile +++ b/drivers/mtd/nand/raw/Makefile @@ -61,7 +61,6 @@ obj-$(CONFIG_NAND_FSL_IFC) += fsl_ifc_nand.o obj-$(CONFIG_NAND_KIRKWOOD) += kirkwood_nand.o obj-$(CONFIG_NAND_KMETER1) += kmeter1_nand.o obj-$(CONFIG_NAND_LPC32XX_MLC) += lpc32xx_nand_mlc.o -obj-$(CONFIG_NAND_LPC32XX_SLC) += lpc32xx_nand_slc.o obj-$(CONFIG_NAND_VF610_NFC) += vf610_nfc.o obj-$(CONFIG_NAND_MESON) += meson_nand.o obj-$(CONFIG_NAND_MXC) += mxc_nand.o diff --git a/drivers/mtd/nand/raw/lpc32xx_nand_slc.c b/drivers/mtd/nand/raw/lpc32xx_nand_slc.c deleted file mode 100644 index 109c31fb4d1..00000000000 --- a/drivers/mtd/nand/raw/lpc32xx_nand_slc.c +++ /dev/null @@ -1,587 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * LPC32xx SLC NAND flash controller driver - * - * (C) Copyright 2015-2018 Vladimir Zapolskiy - * Copyright (c) 2015 Tyco Fire Protection Products. - * - * Hardware ECC support original source code - * Copyright (C) 2008 by NXP Semiconductors - * Author: Kevin Wells - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct lpc32xx_nand_slc_regs { - u32 data; - u32 addr; - u32 cmd; - u32 stop; - u32 ctrl; - u32 cfg; - u32 stat; - u32 int_stat; - u32 ien; - u32 isr; - u32 icr; - u32 tac; - u32 tc; - u32 ecc; - u32 dma_data; -}; - -/* CFG register */ -#define CFG_CE_LOW (1 << 5) -#define CFG_DMA_ECC (1 << 4) /* Enable DMA ECC bit */ -#define CFG_ECC_EN (1 << 3) /* ECC enable bit */ -#define CFG_DMA_BURST (1 << 2) /* DMA burst bit */ -#define CFG_DMA_DIR (1 << 1) /* DMA write(0)/read(1) bit */ - -/* CTRL register */ -#define CTRL_SW_RESET (1 << 2) -#define CTRL_ECC_CLEAR (1 << 1) /* Reset ECC bit */ -#define CTRL_DMA_START (1 << 0) /* Start DMA channel bit */ - -/* STAT register */ -#define STAT_DMA_FIFO (1 << 2) /* DMA FIFO has data bit */ -#define STAT_NAND_READY (1 << 0) - -/* INT_STAT register */ -#define INT_STAT_TC (1 << 1) -#define INT_STAT_RDY (1 << 0) - -/* TAC register bits, be aware of overflows */ -#define TAC_W_RDY(n) (max_t(uint32_t, (n), 0xF) << 28) -#define TAC_W_WIDTH(n) (max_t(uint32_t, (n), 0xF) << 24) -#define TAC_W_HOLD(n) (max_t(uint32_t, (n), 0xF) << 20) -#define TAC_W_SETUP(n) (max_t(uint32_t, (n), 0xF) << 16) -#define TAC_R_RDY(n) (max_t(uint32_t, (n), 0xF) << 12) -#define TAC_R_WIDTH(n) (max_t(uint32_t, (n), 0xF) << 8) -#define TAC_R_HOLD(n) (max_t(uint32_t, (n), 0xF) << 4) -#define TAC_R_SETUP(n) (max_t(uint32_t, (n), 0xF) << 0) - -/* NAND ECC Layout for small page NAND devices - * Note: For large page devices, the default layouts are used. */ -static struct nand_ecclayout lpc32xx_nand_oob_16 = { - .eccbytes = 6, - .eccpos = { 10, 11, 12, 13, 14, 15, }, - .oobfree = { - { .offset = 0, .length = 4, }, - { .offset = 6, .length = 4, }, - } -}; - -#if defined(CONFIG_DMA_LPC32XX) && !defined(CONFIG_XPL_BUILD) -#define ECCSTEPS (CONFIG_SYS_NAND_PAGE_SIZE / CFG_SYS_NAND_ECCSIZE) - -/* - * DMA Descriptors - * For Large Block: 17 descriptors = ((16 Data and ECC Read) + 1 Spare Area) - * For Small Block: 5 descriptors = ((4 Data and ECC Read) + 1 Spare Area) - */ -static struct lpc32xx_dmac_ll dmalist[ECCSTEPS * 2 + 1]; -static u32 ecc_buffer[8]; /* MAX ECC size */ -static unsigned int dmachan = (unsigned int)-1; /* Invalid channel */ - -/* - * Helper macro for the DMA client (i.e. NAND SLC): - * - to write the next DMA linked list item address - * (see arch/include/asm/arch-lpc32xx/dma.h). - * - to assign the DMA data register to DMA source or destination address. - * - to assign the ECC register to DMA source or destination address. - */ -#define lpc32xx_dmac_next_lli(x) ((u32)x) -#define lpc32xx_dmac_set_dma_data() ((u32)&lpc32xx_nand_slc_regs->dma_data) -#define lpc32xx_dmac_set_ecc() ((u32)&lpc32xx_nand_slc_regs->ecc) -#endif - -static struct lpc32xx_nand_slc_regs __iomem *lpc32xx_nand_slc_regs - = (struct lpc32xx_nand_slc_regs __iomem *)SLC_NAND_BASE; - -static void lpc32xx_nand_init(void) -{ - uint32_t hclk = get_hclk_clk_rate(); - - /* Reset SLC NAND controller */ - writel(CTRL_SW_RESET, &lpc32xx_nand_slc_regs->ctrl); - - /* 8-bit bus, no DMA, no ECC, ordinary CE signal */ - writel(0, &lpc32xx_nand_slc_regs->cfg); - - /* Interrupts disabled and cleared */ - writel(0, &lpc32xx_nand_slc_regs->ien); - writel(INT_STAT_TC | INT_STAT_RDY, - &lpc32xx_nand_slc_regs->icr); - - /* Configure NAND flash timings */ - writel(TAC_W_RDY(CFG_LPC32XX_NAND_SLC_WDR_CLKS) | - TAC_W_WIDTH(hclk / CFG_LPC32XX_NAND_SLC_WWIDTH) | - TAC_W_HOLD(hclk / CFG_LPC32XX_NAND_SLC_WHOLD) | - TAC_W_SETUP(hclk / CFG_LPC32XX_NAND_SLC_WSETUP) | - TAC_R_RDY(CFG_LPC32XX_NAND_SLC_RDR_CLKS) | - TAC_R_WIDTH(hclk / CFG_LPC32XX_NAND_SLC_RWIDTH) | - TAC_R_HOLD(hclk / CFG_LPC32XX_NAND_SLC_RHOLD) | - TAC_R_SETUP(hclk / CFG_LPC32XX_NAND_SLC_RSETUP), - &lpc32xx_nand_slc_regs->tac); -} - -static void lpc32xx_nand_cmd_ctrl(struct mtd_info *mtd, - int cmd, unsigned int ctrl) -{ - debug("ctrl: 0x%08x, cmd: 0x%08x\n", ctrl, cmd); - - if (ctrl & NAND_NCE) - setbits_le32(&lpc32xx_nand_slc_regs->cfg, CFG_CE_LOW); - else - clrbits_le32(&lpc32xx_nand_slc_regs->cfg, CFG_CE_LOW); - - if (cmd == NAND_CMD_NONE) - return; - - if (ctrl & NAND_CLE) - writel(cmd & 0xFF, &lpc32xx_nand_slc_regs->cmd); - else if (ctrl & NAND_ALE) - writel(cmd & 0xFF, &lpc32xx_nand_slc_regs->addr); -} - -static int lpc32xx_nand_dev_ready(struct mtd_info *mtd) -{ - return readl(&lpc32xx_nand_slc_regs->stat) & STAT_NAND_READY; -} - -#if defined(CONFIG_DMA_LPC32XX) && !defined(CONFIG_XPL_BUILD) -/* - * Prepares DMA descriptors for NAND RD/WR operations - * If the size is < 256 Bytes then it is assumed to be - * an OOB transfer - */ -static void lpc32xx_nand_dma_configure(struct nand_chip *chip, - const u8 *buffer, int size, - int read) -{ - u32 i, dmasrc, ctrl, ecc_ctrl, oob_ctrl, dmadst; - struct lpc32xx_dmac_ll *dmalist_cur; - struct lpc32xx_dmac_ll *dmalist_cur_ecc; - - /* - * CTRL descriptor entry for reading ECC - * Copy Multiple times to sync DMA with Flash Controller - */ - ecc_ctrl = 0x5 | - DMAC_CHAN_SRC_BURST_1 | - DMAC_CHAN_DEST_BURST_1 | - DMAC_CHAN_SRC_WIDTH_32 | - DMAC_CHAN_DEST_WIDTH_32 | - DMAC_CHAN_DEST_AHB1; - - /* CTRL descriptor entry for reading/writing Data */ - ctrl = (CFG_SYS_NAND_ECCSIZE / 4) | - DMAC_CHAN_SRC_BURST_4 | - DMAC_CHAN_DEST_BURST_4 | - DMAC_CHAN_SRC_WIDTH_32 | - DMAC_CHAN_DEST_WIDTH_32 | - DMAC_CHAN_DEST_AHB1; - - /* CTRL descriptor entry for reading/writing Spare Area */ - oob_ctrl = (CONFIG_SYS_NAND_OOBSIZE / 4) | - DMAC_CHAN_SRC_BURST_4 | - DMAC_CHAN_DEST_BURST_4 | - DMAC_CHAN_SRC_WIDTH_32 | - DMAC_CHAN_DEST_WIDTH_32 | - DMAC_CHAN_DEST_AHB1; - - if (read) { - dmasrc = lpc32xx_dmac_set_dma_data(); - dmadst = (u32)buffer; - ctrl |= DMAC_CHAN_DEST_AUTOINC; - } else { - dmadst = lpc32xx_dmac_set_dma_data(); - dmasrc = (u32)buffer; - ctrl |= DMAC_CHAN_SRC_AUTOINC; - } - - /* - * Write Operation Sequence for Small Block NAND - * ---------------------------------------------------------- - * 1. X'fer 256 bytes of data from Memory to Flash. - * 2. Copy generated ECC data from Register to Spare Area - * 3. X'fer next 256 bytes of data from Memory to Flash. - * 4. Copy generated ECC data from Register to Spare Area. - * 5. X'fer 16 byets of Spare area from Memory to Flash. - * Read Operation Sequence for Small Block NAND - * ---------------------------------------------------------- - * 1. X'fer 256 bytes of data from Flash to Memory. - * 2. Copy generated ECC data from Register to ECC calc Buffer. - * 3. X'fer next 256 bytes of data from Flash to Memory. - * 4. Copy generated ECC data from Register to ECC calc Buffer. - * 5. X'fer 16 bytes of Spare area from Flash to Memory. - * Write Operation Sequence for Large Block NAND - * ---------------------------------------------------------- - * 1. Steps(1-4) of Write Operations repeate for four times - * which generates 16 DMA descriptors to X'fer 2048 bytes of - * data & 32 bytes of ECC data. - * 2. X'fer 64 bytes of Spare area from Memory to Flash. - * Read Operation Sequence for Large Block NAND - * ---------------------------------------------------------- - * 1. Steps(1-4) of Read Operations repeate for four times - * which generates 16 DMA descriptors to X'fer 2048 bytes of - * data & 32 bytes of ECC data. - * 2. X'fer 64 bytes of Spare area from Flash to Memory. - */ - - for (i = 0; i < size/CFG_SYS_NAND_ECCSIZE; i++) { - dmalist_cur = &dmalist[i * 2]; - dmalist_cur_ecc = &dmalist[(i * 2) + 1]; - - dmalist_cur->dma_src = (read ? (dmasrc) : (dmasrc + (i*256))); - dmalist_cur->dma_dest = (read ? (dmadst + (i*256)) : dmadst); - dmalist_cur->next_lli = lpc32xx_dmac_next_lli(dmalist_cur_ecc); - dmalist_cur->next_ctrl = ctrl; - - dmalist_cur_ecc->dma_src = lpc32xx_dmac_set_ecc(); - dmalist_cur_ecc->dma_dest = (u32)&ecc_buffer[i]; - dmalist_cur_ecc->next_lli = - lpc32xx_dmac_next_lli(&dmalist[(i * 2) + 2]); - dmalist_cur_ecc->next_ctrl = ecc_ctrl; - } - - if (i) { /* Data only transfer */ - dmalist_cur_ecc = &dmalist[(i * 2) - 1]; - dmalist_cur_ecc->next_lli = 0; - dmalist_cur_ecc->next_ctrl |= DMAC_CHAN_INT_TC_EN; - return; - } - - /* OOB only transfer */ - if (read) { - dmasrc = lpc32xx_dmac_set_dma_data(); - dmadst = (u32)buffer; - oob_ctrl |= DMAC_CHAN_DEST_AUTOINC; - } else { - dmadst = lpc32xx_dmac_set_dma_data(); - dmasrc = (u32)buffer; - oob_ctrl |= DMAC_CHAN_SRC_AUTOINC; - } - - /* Read/ Write Spare Area Data To/From Flash */ - dmalist_cur = &dmalist[i * 2]; - dmalist_cur->dma_src = dmasrc; - dmalist_cur->dma_dest = dmadst; - dmalist_cur->next_lli = 0; - dmalist_cur->next_ctrl = (oob_ctrl | DMAC_CHAN_INT_TC_EN); -} - -static void lpc32xx_nand_xfer(struct mtd_info *mtd, const u8 *buf, - int len, int read) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - u32 config; - int ret; - - /* DMA Channel Configuration */ - config = (read ? DMAC_CHAN_FLOW_D_P2M : DMAC_CHAN_FLOW_D_M2P) | - (read ? DMAC_DEST_PERIP(0) : DMAC_DEST_PERIP(DMA_PERID_NAND1)) | - (read ? DMAC_SRC_PERIP(DMA_PERID_NAND1) : DMAC_SRC_PERIP(0)) | - DMAC_CHAN_ENABLE; - - /* Prepare DMA descriptors */ - lpc32xx_nand_dma_configure(chip, buf, len, read); - - /* Setup SLC controller and start transfer */ - if (read) - setbits_le32(&lpc32xx_nand_slc_regs->cfg, CFG_DMA_DIR); - else /* NAND_ECC_WRITE */ - clrbits_le32(&lpc32xx_nand_slc_regs->cfg, CFG_DMA_DIR); - setbits_le32(&lpc32xx_nand_slc_regs->cfg, CFG_DMA_BURST); - - /* Write length for new transfers */ - if (!((readl(&lpc32xx_nand_slc_regs->stat) & STAT_DMA_FIFO) | - readl(&lpc32xx_nand_slc_regs->tc))) { - int tmp = (len != mtd->oobsize) ? mtd->oobsize : 0; - writel(len + tmp, &lpc32xx_nand_slc_regs->tc); - } - - setbits_le32(&lpc32xx_nand_slc_regs->ctrl, CTRL_DMA_START); - - /* Start DMA transfers */ - ret = lpc32xx_dma_start_xfer(dmachan, dmalist, config); - if (unlikely(ret < 0)) - BUG(); - - /* Wait for NAND to be ready */ - while (!lpc32xx_nand_dev_ready(mtd)) - ; - - /* Wait till DMA transfer is DONE */ - if (lpc32xx_dma_wait_status(dmachan)) - pr_err("NAND DMA transfer error!\r\n"); - - /* Stop DMA & HW ECC */ - clrbits_le32(&lpc32xx_nand_slc_regs->ctrl, CTRL_DMA_START); - clrbits_le32(&lpc32xx_nand_slc_regs->cfg, - CFG_DMA_DIR | CFG_DMA_BURST | CFG_ECC_EN | CFG_DMA_ECC); -} - -static u32 slc_ecc_copy_to_buffer(u8 *spare, const u32 *ecc, int count) -{ - int i; - for (i = 0; i < (count * CFG_SYS_NAND_ECCBYTES); - i += CFG_SYS_NAND_ECCBYTES) { - u32 ce = ecc[i / CFG_SYS_NAND_ECCBYTES]; - ce = ~(ce << 2) & 0xFFFFFF; - spare[i+2] = (u8)(ce & 0xFF); ce >>= 8; - spare[i+1] = (u8)(ce & 0xFF); ce >>= 8; - spare[i] = (u8)(ce & 0xFF); - } - return 0; -} - -static int lpc32xx_ecc_calculate(struct mtd_info *mtd, const uint8_t *dat, - uint8_t *ecc_code) -{ - return slc_ecc_copy_to_buffer(ecc_code, ecc_buffer, ECCSTEPS); -} - -/* - * Enables and prepares SLC NAND controller - * for doing data transfers with H/W ECC enabled. - */ -static void lpc32xx_hwecc_enable(struct mtd_info *mtd, int mode) -{ - /* Clear ECC */ - writel(CTRL_ECC_CLEAR, &lpc32xx_nand_slc_regs->ctrl); - - /* Setup SLC controller for H/W ECC operations */ - setbits_le32(&lpc32xx_nand_slc_regs->cfg, CFG_ECC_EN | CFG_DMA_ECC); -} - -/* - * lpc32xx_correct_data - [NAND Interface] Detect and correct bit error(s) - * mtd: MTD block structure - * dat: raw data read from the chip - * read_ecc: ECC from the chip - * calc_ecc: the ECC calculated from raw data - * - * Detect and correct a 1 bit error for 256 byte block - */ -int lpc32xx_correct_data(struct mtd_info *mtd, u_char *dat, - u_char *read_ecc, u_char *calc_ecc) -{ - unsigned int i; - int ret1, ret2 = 0; - u_char *r = read_ecc; - u_char *c = calc_ecc; - u16 data_offset = 0; - - for (i = 0 ; i < ECCSTEPS ; i++) { - r += CFG_SYS_NAND_ECCBYTES; - c += CFG_SYS_NAND_ECCBYTES; - data_offset += CFG_SYS_NAND_ECCSIZE; - - ret1 = nand_correct_data(mtd, dat + data_offset, r, c); - if (ret1 < 0) - return -EBADMSG; - else - ret2 += ret1; - } - - return ret2; -} - -static void lpc32xx_dma_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) -{ - lpc32xx_nand_xfer(mtd, buf, len, 1); -} - -static void lpc32xx_dma_write_buf(struct mtd_info *mtd, const uint8_t *buf, - int len) -{ - lpc32xx_nand_xfer(mtd, buf, len, 0); -} - -/* Reuse the logic from "nand_read_page_hwecc()" */ -static int lpc32xx_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int oob_required, int page) -{ - int i; - int stat; - uint8_t *p = buf; - uint8_t *ecc_calc = chip->buffers->ecccalc; - uint8_t *ecc_code = chip->buffers->ecccode; - uint32_t *eccpos = chip->ecc.layout->eccpos; - unsigned int max_bitflips = 0; - - /* - * As per the "LPC32x0 and LPC32x0/01 User manual" table 173 notes - * and section 9.7, the NAND SLC & DMA allowed single DMA transaction - * of a page size using DMA controller scatter/gather mode through - * linked list; the ECC read is done without any software intervention. - */ - - lpc32xx_hwecc_enable(mtd, NAND_ECC_READ); - lpc32xx_dma_read_buf(mtd, p, chip->ecc.size * chip->ecc.steps); - lpc32xx_ecc_calculate(mtd, p, &ecc_calc[0]); - lpc32xx_dma_read_buf(mtd, chip->oob_poi, mtd->oobsize); - - for (i = 0; i < chip->ecc.total; i++) - ecc_code[i] = chip->oob_poi[eccpos[i]]; - - stat = chip->ecc.correct(mtd, p, &ecc_code[0], &ecc_calc[0]); - if (stat < 0) - mtd->ecc_stats.failed++; - else { - mtd->ecc_stats.corrected += stat; - max_bitflips = max_t(unsigned int, max_bitflips, stat); - } - - return max_bitflips; -} - -/* Reuse the logic from "nand_write_page_hwecc()" */ -static int lpc32xx_write_page_hwecc(struct mtd_info *mtd, - struct nand_chip *chip, - const uint8_t *buf, int oob_required, - int page) -{ - int i; - uint8_t *ecc_calc = chip->buffers->ecccalc; - const uint8_t *p = buf; - uint32_t *eccpos = chip->ecc.layout->eccpos; - - /* - * As per the "LPC32x0 and LPC32x0/01 User manual" table 173 notes - * and section 9.7, the NAND SLC & DMA allowed single DMA transaction - * of a page size using DMA controller scatter/gather mode through - * linked list; the ECC read is done without any software intervention. - */ - - lpc32xx_hwecc_enable(mtd, NAND_ECC_WRITE); - lpc32xx_dma_write_buf(mtd, p, chip->ecc.size * chip->ecc.steps); - lpc32xx_ecc_calculate(mtd, p, &ecc_calc[0]); - - for (i = 0; i < chip->ecc.total; i++) - chip->oob_poi[eccpos[i]] = ecc_calc[i]; - - lpc32xx_dma_write_buf(mtd, chip->oob_poi, mtd->oobsize); - - return 0; -} -#else -static void lpc32xx_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) -{ - while (len-- > 0) - *buf++ = readl(&lpc32xx_nand_slc_regs->data); -} - -static void lpc32xx_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) -{ - while (len-- > 0) - writel(*buf++, &lpc32xx_nand_slc_regs->data); -} -#endif - -static uint8_t lpc32xx_read_byte(struct mtd_info *mtd) -{ - return readl(&lpc32xx_nand_slc_regs->data); -} - -static void lpc32xx_write_byte(struct mtd_info *mtd, uint8_t byte) -{ - writel(byte, &lpc32xx_nand_slc_regs->data); -} - -/* - * LPC32xx has only one SLC NAND controller, don't utilize - * CONFIG_SYS_NAND_SELF_INIT to be able to reuse this function - * both in SPL NAND and U-Boot images. - */ -int board_nand_init(struct nand_chip *lpc32xx_chip) -{ -#if defined(CONFIG_DMA_LPC32XX) && !defined(CONFIG_XPL_BUILD) - int ret; - - /* Acquire a channel for our use */ - ret = lpc32xx_dma_get_channel(); - if (unlikely(ret < 0)) { - pr_info("Unable to get free DMA channel for NAND transfers\n"); - return -1; - } - dmachan = (unsigned int)ret; -#endif - - lpc32xx_chip->cmd_ctrl = lpc32xx_nand_cmd_ctrl; - lpc32xx_chip->dev_ready = lpc32xx_nand_dev_ready; - - /* - * The implementation of these functions is quite common, but - * they MUST be defined, because access to data register - * is strictly 32-bit aligned. - */ - lpc32xx_chip->read_byte = lpc32xx_read_byte; - lpc32xx_chip->write_byte = lpc32xx_write_byte; - -#if defined(CONFIG_DMA_LPC32XX) && !defined(CONFIG_XPL_BUILD) - /* Hardware ECC calculation is supported when DMA driver is selected */ - lpc32xx_chip->ecc.mode = NAND_ECC_HW; - - lpc32xx_chip->read_buf = lpc32xx_dma_read_buf; - lpc32xx_chip->write_buf = lpc32xx_dma_write_buf; - - lpc32xx_chip->ecc.calculate = lpc32xx_ecc_calculate; - lpc32xx_chip->ecc.correct = lpc32xx_correct_data; - lpc32xx_chip->ecc.hwctl = lpc32xx_hwecc_enable; - lpc32xx_chip->chip_delay = 2000; - - lpc32xx_chip->ecc.read_page = lpc32xx_read_page_hwecc; - lpc32xx_chip->ecc.write_page = lpc32xx_write_page_hwecc; - lpc32xx_chip->options |= NAND_NO_SUBPAGE_WRITE; -#else - /* - * Hardware ECC calculation is not supported by the driver, - * because it requires DMA support, see LPC32x0 User Manual, - * note after SLC_ECC register description (UM10326, p.198) - */ - lpc32xx_chip->ecc.mode = NAND_ECC_SOFT; - - /* - * The implementation of these functions is quite common, but - * they MUST be defined, because access to data register - * is strictly 32-bit aligned. - */ - lpc32xx_chip->read_buf = lpc32xx_read_buf; - lpc32xx_chip->write_buf = lpc32xx_write_buf; -#endif - - /* - * These values are predefined - * for both small and large page NAND flash devices. - */ - lpc32xx_chip->ecc.size = CFG_SYS_NAND_ECCSIZE; - lpc32xx_chip->ecc.bytes = CFG_SYS_NAND_ECCBYTES; - lpc32xx_chip->ecc.strength = 1; - - if (CONFIG_SYS_NAND_PAGE_SIZE != NAND_LARGE_BLOCK_PAGE_SIZE) - lpc32xx_chip->ecc.layout = &lpc32xx_nand_oob_16; - -#if defined(CONFIG_SYS_NAND_USE_FLASH_BBT) - lpc32xx_chip->bbt_options |= NAND_BBT_USE_FLASH; -#endif - - /* Initialize NAND interface */ - lpc32xx_nand_init(); - - return 0; -} From cb34f23bdb6f869bac4e4cad8407e7b54fdfce7a Mon Sep 17 00:00:00 2001 From: Tom Rini Date: Fri, 11 Jul 2025 09:19:52 -0600 Subject: [PATCH 8/9] mtd: nand: raw: Remove unused mxic_nand driver As no platforms use this driver anymore let's go ahead and remove it. Signed-off-by: Tom Rini Reviewed-by: Michael Trimarchi --- drivers/mtd/nand/raw/Kconfig | 6 - drivers/mtd/nand/raw/Makefile | 1 - drivers/mtd/nand/raw/mxic_nand.c | 602 ------------------------------- 3 files changed, 609 deletions(-) delete mode 100644 drivers/mtd/nand/raw/mxic_nand.c diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig index 2099825f4cf..2141347d141 100644 --- a/drivers/mtd/nand/raw/Kconfig +++ b/drivers/mtd/nand/raw/Kconfig @@ -551,12 +551,6 @@ config NAND_MXS_USE_MINIMUM_ECC endif -config NAND_MXIC - bool "Macronix raw NAND controller" - select SYS_NAND_SELF_INIT - help - This selects the Macronix raw NAND controller driver. - config NAND_ZYNQ bool "Support for Zynq Nand controller" select SPL_SYS_NAND_SELF_INIT diff --git a/drivers/mtd/nand/raw/Makefile b/drivers/mtd/nand/raw/Makefile index 97e874ef769..5ffd450e8fe 100644 --- a/drivers/mtd/nand/raw/Makefile +++ b/drivers/mtd/nand/raw/Makefile @@ -74,7 +74,6 @@ obj-$(CONFIG_NAND_OMAP_GPMC) += omap_gpmc.o obj-$(CONFIG_NAND_OMAP_ELM) += omap_elm.o obj-$(CONFIG_NAND_SANDBOX) += sand_nand.o obj-$(CONFIG_NAND_SUNXI) += sunxi_nand.o -obj-$(CONFIG_NAND_MXIC) += mxic_nand.o obj-$(CONFIG_NAND_ZYNQ) += zynq_nand.o obj-$(CONFIG_NAND_STM32_FMC2) += stm32_fmc2_nand.o obj-$(CONFIG_CORTINA_NAND) += cortina_nand.o diff --git a/drivers/mtd/nand/raw/mxic_nand.c b/drivers/mtd/nand/raw/mxic_nand.c deleted file mode 100644 index 0e54b5f6938..00000000000 --- a/drivers/mtd/nand/raw/mxic_nand.c +++ /dev/null @@ -1,602 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) 2021 Macronix International Co., Ltd. - * - * Author: - * Zhengxun Li - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define HC_CFG 0x0 -#define HC_CFG_IF_CFG(x) ((x) << 27) -#define HC_CFG_DUAL_SLAVE BIT(31) -#define HC_CFG_INDIVIDUAL BIT(30) -#define HC_CFG_NIO(x) (((x) / 4) << 27) -#define HC_CFG_TYPE(s, t) ((t) << (23 + ((s) * 2))) -#define HC_CFG_TYPE_SPI_NOR 0 -#define HC_CFG_TYPE_SPI_NAND 1 -#define HC_CFG_TYPE_SPI_RAM 2 -#define HC_CFG_TYPE_RAW_NAND 3 -#define HC_CFG_SLV_ACT(x) ((x) << 21) -#define HC_CFG_CLK_PH_EN BIT(20) -#define HC_CFG_CLK_POL_INV BIT(19) -#define HC_CFG_BIG_ENDIAN BIT(18) -#define HC_CFG_DATA_PASS BIT(17) -#define HC_CFG_IDLE_SIO_LVL(x) ((x) << 16) -#define HC_CFG_MAN_START_EN BIT(3) -#define HC_CFG_MAN_START BIT(2) -#define HC_CFG_MAN_CS_EN BIT(1) -#define HC_CFG_MAN_CS_ASSERT BIT(0) - -#define INT_STS 0x4 -#define INT_STS_EN 0x8 -#define INT_SIG_EN 0xc -#define INT_STS_ALL GENMASK(31, 0) -#define INT_RDY_PIN BIT(26) -#define INT_RDY_SR BIT(25) -#define INT_LNR_SUSP BIT(24) -#define INT_ECC_ERR BIT(17) -#define INT_CRC_ERR BIT(16) -#define INT_LWR_DIS BIT(12) -#define INT_LRD_DIS BIT(11) -#define INT_SDMA_INT BIT(10) -#define INT_DMA_FINISH BIT(9) -#define INT_RX_NOT_FULL BIT(3) -#define INT_RX_NOT_EMPTY BIT(2) -#define INT_TX_NOT_FULL BIT(1) -#define INT_TX_EMPTY BIT(0) - -#define HC_EN 0x10 -#define HC_EN_BIT BIT(0) - -#define TXD(x) (0x14 + ((x) * 4)) -#define RXD 0x24 - -#define SS_CTRL(s) (0x30 + ((s) * 4)) -#define LRD_CFG 0x44 -#define LWR_CFG 0x80 -#define RWW_CFG 0x70 -#define OP_READ BIT(23) -#define OP_DUMMY_CYC(x) ((x) << 17) -#define OP_ADDR_BYTES(x) ((x) << 14) -#define OP_CMD_BYTES(x) (((x) - 1) << 13) -#define OP_OCTA_CRC_EN BIT(12) -#define OP_DQS_EN BIT(11) -#define OP_ENHC_EN BIT(10) -#define OP_PREAMBLE_EN BIT(9) -#define OP_DATA_DDR BIT(8) -#define OP_DATA_BUSW(x) ((x) << 6) -#define OP_ADDR_DDR BIT(5) -#define OP_ADDR_BUSW(x) ((x) << 3) -#define OP_CMD_DDR BIT(2) -#define OP_CMD_BUSW(x) (x) -#define OP_BUSW_1 0 -#define OP_BUSW_2 1 -#define OP_BUSW_4 2 -#define OP_BUSW_8 3 - -#define OCTA_CRC 0x38 -#define OCTA_CRC_IN_EN(s) BIT(3 + ((s) * 16)) -#define OCTA_CRC_CHUNK(s, x) ((fls((x) / 32)) << (1 + ((s) * 16))) -#define OCTA_CRC_OUT_EN(s) BIT(0 + ((s) * 16)) - -#define ONFI_DIN_CNT(s) (0x3c + (s)) - -#define LRD_CTRL 0x48 -#define RWW_CTRL 0x74 -#define LWR_CTRL 0x84 -#define LMODE_EN BIT(31) -#define LMODE_SLV_ACT(x) ((x) << 21) -#define LMODE_CMD1(x) ((x) << 8) -#define LMODE_CMD0(x) (x) - -#define LRD_ADDR 0x4c -#define LWR_ADDR 0x88 -#define LRD_RANGE 0x50 -#define LWR_RANGE 0x8c - -#define AXI_SLV_ADDR 0x54 - -#define DMAC_RD_CFG 0x58 -#define DMAC_WR_CFG 0x94 -#define DMAC_CFG_PERIPH_EN BIT(31) -#define DMAC_CFG_ALLFLUSH_EN BIT(30) -#define DMAC_CFG_LASTFLUSH_EN BIT(29) -#define DMAC_CFG_QE(x) (((x) + 1) << 16) -#define DMAC_CFG_BURST_LEN(x) (((x) + 1) << 12) -#define DMAC_CFG_BURST_SZ(x) ((x) << 8) -#define DMAC_CFG_DIR_READ BIT(1) -#define DMAC_CFG_START BIT(0) - -#define DMAC_RD_CNT 0x5c -#define DMAC_WR_CNT 0x98 - -#define SDMA_ADDR 0x60 - -#define DMAM_CFG 0x64 -#define DMAM_CFG_START BIT(31) -#define DMAM_CFG_CONT BIT(30) -#define DMAM_CFG_SDMA_GAP(x) (fls((x) / 8192) << 2) -#define DMAM_CFG_DIR_READ BIT(1) -#define DMAM_CFG_EN BIT(0) - -#define DMAM_CNT 0x68 - -#define LNR_TIMER_TH 0x6c - -#define RDM_CFG0 0x78 -#define RDM_CFG0_POLY(x) (x) - -#define RDM_CFG1 0x7c -#define RDM_CFG1_RDM_EN BIT(31) -#define RDM_CFG1_SEED(x) (x) - -#define LWR_SUSP_CTRL 0x90 -#define LWR_SUSP_CTRL_EN BIT(31) - -#define DMAS_CTRL 0x9c -#define DMAS_CTRL_EN BIT(31) -#define DMAS_CTRL_DIR_READ BIT(30) - -#define DATA_STROB 0xa0 -#define DATA_STROB_EDO_EN BIT(2) -#define DATA_STROB_INV_POL BIT(1) -#define DATA_STROB_DELAY_2CYC BIT(0) - -#define IDLY_CODE(x) (0xa4 + ((x) * 4)) -#define IDLY_CODE_VAL(x, v) ((v) << (((x) % 4) * 8)) - -#define GPIO 0xc4 -#define GPIO_PT(x) BIT(3 + ((x) * 16)) -#define GPIO_RESET(x) BIT(2 + ((x) * 16)) -#define GPIO_HOLDB(x) BIT(1 + ((x) * 16)) -#define GPIO_WPB(x) BIT((x) * 16) - -#define HC_VER 0xd0 - -#define HW_TEST(x) (0xe0 + ((x) * 4)) - -#define MXIC_NFC_MAX_CLK_HZ 50000000 -#define IRQ_TIMEOUT 1000 - -struct mxic_nand_ctrl { - struct clk *send_clk; - struct clk *send_dly_clk; - void __iomem *regs; - struct nand_chip nand_chip; -}; - -/* - * struct mxic_nfc_command_format - Defines NAND flash command format - * @start_cmd: First cycle command (Start command) - * @end_cmd: Second cycle command (Last command) - * @addr_len: Number of address cycles required to send the address - * @read: Direction of command - */ - -struct mxic_nfc_command_format { - int start_cmd; - int end_cmd; - u8 addr_len; - bool read; -}; - -/* The NAND flash operations command format */ -static const struct mxic_nfc_command_format mxic_nand_commands[] = { - {NAND_CMD_READ0, NAND_CMD_READSTART, 5, 1 }, - {NAND_CMD_RNDOUT, NAND_CMD_RNDOUTSTART, 2, 1 }, - {NAND_CMD_READID, NAND_CMD_NONE, 1, 1 }, - {NAND_CMD_STATUS, NAND_CMD_NONE, 0, 1 }, - {NAND_CMD_SEQIN, NAND_CMD_NONE, 5, 0 }, - {NAND_CMD_PAGEPROG, NAND_CMD_NONE, 0, 0 }, - {NAND_CMD_CACHEDPROG, NAND_CMD_NONE, 0, 0 }, - {NAND_CMD_RNDIN, NAND_CMD_NONE, 2, 0 }, - {NAND_CMD_ERASE1, NAND_CMD_NONE, 3, 0 }, - {NAND_CMD_ERASE2, NAND_CMD_NONE, 0, 0 }, - {NAND_CMD_RESET, NAND_CMD_NONE, 0, 0 }, - {NAND_CMD_PARAM, NAND_CMD_NONE, 1, 1 }, - {NAND_CMD_GET_FEATURES, NAND_CMD_NONE, 1, 1 }, - {NAND_CMD_SET_FEATURES, NAND_CMD_NONE, 1, 0 }, - {NAND_CMD_NONE, NAND_CMD_NONE, 0, 0 }, -}; - -static int mxic_nfc_clk_enable(struct mxic_nand_ctrl *nfc) -{ - int ret; - - ret = clk_prepare_enable(nfc->send_clk); - if (ret) - return ret; - - ret = clk_prepare_enable(nfc->send_dly_clk); - if (ret) - goto err_send_dly_clk; - - return ret; - -err_send_dly_clk: - clk_disable_unprepare(nfc->send_clk); - - return ret; -} - -static void mxic_nfc_clk_disable(struct mxic_nand_ctrl *nfc) -{ - clk_disable_unprepare(nfc->send_clk); - clk_disable_unprepare(nfc->send_dly_clk); -} - -static void mxic_nfc_set_input_delay(struct mxic_nand_ctrl *nfc, u8 idly_code) -{ - writel(IDLY_CODE_VAL(0, idly_code) | - IDLY_CODE_VAL(1, idly_code) | - IDLY_CODE_VAL(2, idly_code) | - IDLY_CODE_VAL(3, idly_code), - nfc->regs + IDLY_CODE(0)); - writel(IDLY_CODE_VAL(4, idly_code) | - IDLY_CODE_VAL(5, idly_code) | - IDLY_CODE_VAL(6, idly_code) | - IDLY_CODE_VAL(7, idly_code), - nfc->regs + IDLY_CODE(1)); -} - -static int mxic_nfc_clk_setup(struct mxic_nand_ctrl *nfc, unsigned long freq) -{ - int ret; - - ret = clk_set_rate(nfc->send_clk, freq); - if (ret) - return ret; - - ret = clk_set_rate(nfc->send_dly_clk, freq); - if (ret) - return ret; - - /* - * A constant delay range from 0x0 ~ 0x1F for input delay, - * the unit is 78 ps, the max input delay is 2.418 ns. - */ - mxic_nfc_set_input_delay(nfc, 0xf); - - return 0; -} - -static int mxic_nfc_set_freq(struct mxic_nand_ctrl *nfc, unsigned long freq) -{ - int ret; - - if (freq > MXIC_NFC_MAX_CLK_HZ) - freq = MXIC_NFC_MAX_CLK_HZ; - - mxic_nfc_clk_disable(nfc); - ret = mxic_nfc_clk_setup(nfc, freq); - if (ret) - return ret; - - ret = mxic_nfc_clk_enable(nfc); - if (ret) - return ret; - - return 0; -} - -static void mxic_nfc_hw_init(struct mxic_nand_ctrl *nfc) -{ - writel(HC_CFG_NIO(8) | HC_CFG_TYPE(1, HC_CFG_TYPE_RAW_NAND) | - HC_CFG_SLV_ACT(0) | HC_CFG_MAN_CS_EN | - HC_CFG_IDLE_SIO_LVL(1), nfc->regs + HC_CFG); - writel(INT_STS_ALL, nfc->regs + INT_STS_EN); - writel(INT_RDY_PIN, nfc->regs + INT_SIG_EN); - writel(0x0, nfc->regs + ONFI_DIN_CNT(0)); - writel(0, nfc->regs + LRD_CFG); - writel(0, nfc->regs + LRD_CTRL); - writel(0x0, nfc->regs + HC_EN); -} - -static void mxic_nfc_cs_enable(struct mxic_nand_ctrl *nfc) -{ - writel(readl(nfc->regs + HC_CFG) | HC_CFG_MAN_CS_EN, - nfc->regs + HC_CFG); - writel(HC_CFG_MAN_CS_ASSERT | readl(nfc->regs + HC_CFG), - nfc->regs + HC_CFG); -} - -static void mxic_nfc_cs_disable(struct mxic_nand_ctrl *nfc) -{ - writel(~HC_CFG_MAN_CS_ASSERT & readl(nfc->regs + HC_CFG), - nfc->regs + HC_CFG); -} - -static int mxic_nfc_data_xfer(struct mxic_nand_ctrl *nfc, const void *txbuf, - void *rxbuf, unsigned int len) -{ - unsigned int pos = 0; - - while (pos < len) { - unsigned int nbytes = len - pos; - u32 data = 0xffffffff; - u32 sts; - int ret; - - if (nbytes > 4) - nbytes = 4; - - if (txbuf) - memcpy(&data, txbuf + pos, nbytes); - - ret = readl_poll_timeout(nfc->regs + INT_STS, sts, - sts & INT_TX_EMPTY, 1000000); - if (ret) - return ret; - - writel(data, nfc->regs + TXD(nbytes % 4)); - - ret = readl_poll_timeout(nfc->regs + INT_STS, sts, - sts & INT_TX_EMPTY, 1000000); - if (ret) - return ret; - - ret = readl_poll_timeout(nfc->regs + INT_STS, sts, - sts & INT_RX_NOT_EMPTY, 1000000); - if (ret) - return ret; - - data = readl(nfc->regs + RXD); - if (rxbuf) { - data >>= (8 * (4 - nbytes)); - memcpy(rxbuf + pos, &data, nbytes); - } - - WARN_ON(readl(nfc->regs + INT_STS) & INT_RX_NOT_EMPTY); - - pos += nbytes; - } - - return 0; -} - -static uint8_t mxic_nfc_read_byte(struct mtd_info *mtd) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - struct mxic_nand_ctrl *nfc = nand_get_controller_data(chip); - u8 data; - - writel(0x0, nfc->regs + ONFI_DIN_CNT(0)); - writel(OP_DATA_BUSW(OP_BUSW_8) | OP_DUMMY_CYC(0x3F) | - OP_READ, nfc->regs + SS_CTRL(0)); - - mxic_nfc_data_xfer(nfc, NULL, &data, 1); - - return data; -} - -static void mxic_nfc_read_buf(struct mtd_info *mtd, uint8_t *rxbuf, int rlen) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - struct mxic_nand_ctrl *nfc = nand_get_controller_data(chip); - - writel(0x0, nfc->regs + ONFI_DIN_CNT(0)); - writel(OP_DATA_BUSW(OP_BUSW_8) | OP_DUMMY_CYC(0x3F) | - OP_READ, nfc->regs + SS_CTRL(0)); - - mxic_nfc_data_xfer(nfc, NULL, rxbuf, rlen); -} - -static void mxic_nfc_write_buf(struct mtd_info *mtd, const uint8_t *txbuf, - int wlen) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - struct mxic_nand_ctrl *nfc = nand_get_controller_data(chip); - - writel(wlen, nfc->regs + ONFI_DIN_CNT(0)); - writel(OP_DATA_BUSW(OP_BUSW_8) | OP_DUMMY_CYC(0x3F), - nfc->regs + SS_CTRL(0)); - - mxic_nfc_data_xfer(nfc, txbuf, NULL, wlen); -} - -static void mxic_nfc_cmd_function(struct mtd_info *mtd, unsigned int command, - int column, int page_addr) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - struct mxic_nand_ctrl *nfc = nand_get_controller_data(chip); - const struct mxic_nfc_command_format *cmd = NULL; - u32 sts; - u8 index, addr[5]; - - /* Emulate NAND_CMD_READOOB */ - if (command == NAND_CMD_READOOB) { - column += mtd->writesize; - command = NAND_CMD_READ0; - } - - /* Get the command format */ - for (index = 0; index < ARRAY_SIZE(mxic_nand_commands); index++) - if (command == mxic_nand_commands[index].start_cmd) - break; - - cmd = &mxic_nand_commands[index]; - - if (!(command == NAND_CMD_PAGEPROG || - command == NAND_CMD_CACHEDPROG || - command == NAND_CMD_ERASE2)) - mxic_nfc_cs_disable(nfc); - - mxic_nfc_cs_enable(nfc); - - if (column != -1) { - addr[0] = column; - addr[1] = column >> 8; - - if (page_addr != -1) { - addr[2] = page_addr; - addr[3] = page_addr >> 8; - addr[4] = page_addr >> 16; - } - } else if (page_addr != -1) { - addr[0] = page_addr; - addr[1] = page_addr >> 8; - addr[2] = page_addr >> 16; - } - - writel(0, nfc->regs + HC_EN); - writel(HC_EN_BIT, nfc->regs + HC_EN); - writel(OP_CMD_BUSW(OP_BUSW_8) | OP_DUMMY_CYC(0x3F) | OP_CMD_BYTES(0), - nfc->regs + SS_CTRL(0)); - - mxic_nfc_data_xfer(nfc, &cmd->start_cmd, NULL, 1); - - if (cmd->addr_len) { - writel(OP_ADDR_BUSW(OP_BUSW_8) | OP_DUMMY_CYC(0x3F) | - OP_ADDR_BYTES(cmd->addr_len), nfc->regs + SS_CTRL(0)); - - mxic_nfc_data_xfer(nfc, &addr, NULL, cmd->addr_len); - } - - if (cmd->end_cmd != NAND_CMD_NONE) { - writel(0, nfc->regs + HC_EN); - writel(HC_EN_BIT, nfc->regs + HC_EN); - writel(OP_CMD_BUSW(OP_BUSW_8) | OP_DUMMY_CYC(0x3F) | - OP_CMD_BYTES(0), nfc->regs + SS_CTRL(0)); - - mxic_nfc_data_xfer(nfc, &cmd->end_cmd, NULL, 1); - } - - readl_poll_timeout(nfc->regs + INT_STS, sts, sts & INT_RDY_PIN, - 1000000); - - if (command == NAND_CMD_PAGEPROG || - command == NAND_CMD_CACHEDPROG || - command == NAND_CMD_ERASE2 || - command == NAND_CMD_RESET) { - mxic_nfc_cs_disable(nfc); - } -} - -static int mxic_nfc_setup_data_interface(struct mtd_info *mtd, int chipnr, - const struct nand_data_interface *conf) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - struct mxic_nand_ctrl *nfc = nand_get_controller_data(chip); - const struct nand_sdr_timings *sdr; - unsigned long freq; - int ret; - - sdr = nand_get_sdr_timings(conf); - if (IS_ERR(sdr)) - return PTR_ERR(sdr); - - if (chipnr == NAND_DATA_IFACE_CHECK_ONLY) - return 0; - - freq = 1000000000 / (sdr->tRC_min / 1000); - - ret = mxic_nfc_set_freq(nfc, freq); - if (ret) - WARN_ON("Set freq failed\n"); - - if (sdr->tRC_min < 30000) - writel(DATA_STROB_EDO_EN, nfc->regs + DATA_STROB); - - return 0; -} - -/* Dummy implementation: we don't support multiple chips */ -static void mxic_nfc_select_chip(struct mtd_info *mtd, int chipnr) -{ - switch (chipnr) { - case -1: - case 0: - break; - - default: - BUG(); - } -} - -static int mxic_nfc_probe(struct udevice *dev) -{ - struct mxic_nand_ctrl *nfc = dev_get_priv(dev); - struct nand_chip *nand_chip = &nfc->nand_chip; - struct mtd_info *mtd; - ofnode child; - int err; - - nfc->regs = dev_read_addr_ptr(dev); - - nfc->send_clk = devm_clk_get(dev, "send"); - if (IS_ERR(nfc->send_clk)) - return PTR_ERR(nfc->send_clk); - - nfc->send_dly_clk = devm_clk_get(dev, "send_dly"); - if (IS_ERR(nfc->send_dly_clk)) - return PTR_ERR(nfc->send_dly_clk); - - mtd = nand_to_mtd(nand_chip); - - ofnode_for_each_subnode(child, dev_ofnode(dev)) - nand_set_flash_node(nand_chip, child); - - nand_set_controller_data(nand_chip, nfc); - - nand_chip->select_chip = mxic_nfc_select_chip; - nand_chip->setup_data_interface = mxic_nfc_setup_data_interface; - nand_chip->cmdfunc = mxic_nfc_cmd_function; - nand_chip->read_byte = mxic_nfc_read_byte; - nand_chip->read_buf = mxic_nfc_read_buf; - nand_chip->write_buf = mxic_nfc_write_buf; - - mxic_nfc_hw_init(nfc); - - err = nand_scan(mtd, 1); - if (err) - return err; - - err = nand_register(0, mtd); - if (err) { - dev_err(dev, "Failed to register MTD: %d\n", err); - return err; - } - - return 0; -} - -static const struct udevice_id mxic_nfc_of_ids[] = { - { .compatible = "mxic,multi-itfc-v009-nand-controller" }, - { /* Sentinel */ } -}; - -U_BOOT_DRIVER(mxic_nfc) = { - .name = "mxic_nfc", - .id = UCLASS_MTD, - .of_match = mxic_nfc_of_ids, - .probe = mxic_nfc_probe, - .priv_auto = sizeof(struct mxic_nand_ctrl), -}; - -void board_nand_init(void) -{ - struct udevice *dev; - int ret; - - ret = uclass_get_device_by_driver(UCLASS_MTD, - DM_DRIVER_GET(mxic_nfc), &dev); - if (ret && ret != -ENODEV) - pr_err("Failed to initialize %s. (error %d)\n", dev->name, - ret); -} From 8877bbe67a9be64f2735a45479df196cd22949aa Mon Sep 17 00:00:00 2001 From: Tom Rini Date: Fri, 11 Jul 2025 09:19:45 -0600 Subject: [PATCH 9/9] mtd: nand: raw: Remove unused octeontx_nand driver As no platforms use this driver anymore let's go ahead and remove it. Signed-off-by: Tom Rini --- 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 diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig index 2141347d141..9c8a32bb0a8 100644 --- a/drivers/mtd/nand/raw/Kconfig +++ b/drivers/mtd/nand/raw/Kconfig @@ -568,22 +568,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 5ffd450e8fe..76546a6287b 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 056a6857822..00000000000 --- 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#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 95a9b7126fb..00000000000 --- 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 7d34438fec0..00000000000 --- 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 3b20685fac0..00000000000 --- 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#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< __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 = 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); -}