18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * davinci_nand.c - NAND Flash Driver for DaVinci family chips
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright © 2006 Texas Instruments.
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Port to 2.6.23 Copyright © 2008 by:
88c2ecf20Sopenharmony_ci *   Sander Huijsen <Shuijsen@optelecom-nkf.com>
98c2ecf20Sopenharmony_ci *   Troy Kisky <troy.kisky@boundarydevices.com>
108c2ecf20Sopenharmony_ci *   Dirk Behme <Dirk.Behme@gmail.com>
118c2ecf20Sopenharmony_ci */
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include <linux/kernel.h>
148c2ecf20Sopenharmony_ci#include <linux/module.h>
158c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
168c2ecf20Sopenharmony_ci#include <linux/err.h>
178c2ecf20Sopenharmony_ci#include <linux/iopoll.h>
188c2ecf20Sopenharmony_ci#include <linux/mtd/rawnand.h>
198c2ecf20Sopenharmony_ci#include <linux/mtd/partitions.h>
208c2ecf20Sopenharmony_ci#include <linux/slab.h>
218c2ecf20Sopenharmony_ci#include <linux/of_device.h>
228c2ecf20Sopenharmony_ci#include <linux/of.h>
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#include <linux/platform_data/mtd-davinci.h>
258c2ecf20Sopenharmony_ci#include <linux/platform_data/mtd-davinci-aemif.h>
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci/*
288c2ecf20Sopenharmony_ci * This is a device driver for the NAND flash controller found on the
298c2ecf20Sopenharmony_ci * various DaVinci family chips.  It handles up to four SoC chipselects,
308c2ecf20Sopenharmony_ci * and some flavors of secondary chipselect (e.g. based on A12) as used
318c2ecf20Sopenharmony_ci * with multichip packages.
328c2ecf20Sopenharmony_ci *
338c2ecf20Sopenharmony_ci * The 1-bit ECC hardware is supported, as well as the newer 4-bit ECC
348c2ecf20Sopenharmony_ci * available on chips like the DM355 and OMAP-L137 and needed with the
358c2ecf20Sopenharmony_ci * more error-prone MLC NAND chips.
368c2ecf20Sopenharmony_ci *
378c2ecf20Sopenharmony_ci * This driver assumes EM_WAIT connects all the NAND devices' RDY/nBUSY
388c2ecf20Sopenharmony_ci * outputs in a "wire-AND" configuration, with no per-chip signals.
398c2ecf20Sopenharmony_ci */
408c2ecf20Sopenharmony_cistruct davinci_nand_info {
418c2ecf20Sopenharmony_ci	struct nand_controller	controller;
428c2ecf20Sopenharmony_ci	struct nand_chip	chip;
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci	struct platform_device	*pdev;
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci	bool			is_readmode;
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci	void __iomem		*base;
498c2ecf20Sopenharmony_ci	void __iomem		*vaddr;
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci	void __iomem		*current_cs;
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	uint32_t		mask_chipsel;
548c2ecf20Sopenharmony_ci	uint32_t		mask_ale;
558c2ecf20Sopenharmony_ci	uint32_t		mask_cle;
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci	uint32_t		core_chipsel;
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	struct davinci_aemif_timing	*timing;
608c2ecf20Sopenharmony_ci};
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(davinci_nand_lock);
638c2ecf20Sopenharmony_cistatic bool ecc4_busy;
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_cistatic inline struct davinci_nand_info *to_davinci_nand(struct mtd_info *mtd)
668c2ecf20Sopenharmony_ci{
678c2ecf20Sopenharmony_ci	return container_of(mtd_to_nand(mtd), struct davinci_nand_info, chip);
688c2ecf20Sopenharmony_ci}
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_cistatic inline unsigned int davinci_nand_readl(struct davinci_nand_info *info,
718c2ecf20Sopenharmony_ci		int offset)
728c2ecf20Sopenharmony_ci{
738c2ecf20Sopenharmony_ci	return __raw_readl(info->base + offset);
748c2ecf20Sopenharmony_ci}
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_cistatic inline void davinci_nand_writel(struct davinci_nand_info *info,
778c2ecf20Sopenharmony_ci		int offset, unsigned long value)
788c2ecf20Sopenharmony_ci{
798c2ecf20Sopenharmony_ci	__raw_writel(value, info->base + offset);
808c2ecf20Sopenharmony_ci}
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci/*----------------------------------------------------------------------*/
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci/*
858c2ecf20Sopenharmony_ci * 1-bit hardware ECC ... context maintained for each core chipselect
868c2ecf20Sopenharmony_ci */
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_cistatic inline uint32_t nand_davinci_readecc_1bit(struct mtd_info *mtd)
898c2ecf20Sopenharmony_ci{
908c2ecf20Sopenharmony_ci	struct davinci_nand_info *info = to_davinci_nand(mtd);
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	return davinci_nand_readl(info, NANDF1ECC_OFFSET
938c2ecf20Sopenharmony_ci			+ 4 * info->core_chipsel);
948c2ecf20Sopenharmony_ci}
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_cistatic void nand_davinci_hwctl_1bit(struct nand_chip *chip, int mode)
978c2ecf20Sopenharmony_ci{
988c2ecf20Sopenharmony_ci	struct davinci_nand_info *info;
998c2ecf20Sopenharmony_ci	uint32_t nandcfr;
1008c2ecf20Sopenharmony_ci	unsigned long flags;
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	info = to_davinci_nand(nand_to_mtd(chip));
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	/* Reset ECC hardware */
1058c2ecf20Sopenharmony_ci	nand_davinci_readecc_1bit(nand_to_mtd(chip));
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	spin_lock_irqsave(&davinci_nand_lock, flags);
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	/* Restart ECC hardware */
1108c2ecf20Sopenharmony_ci	nandcfr = davinci_nand_readl(info, NANDFCR_OFFSET);
1118c2ecf20Sopenharmony_ci	nandcfr |= BIT(8 + info->core_chipsel);
1128c2ecf20Sopenharmony_ci	davinci_nand_writel(info, NANDFCR_OFFSET, nandcfr);
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&davinci_nand_lock, flags);
1158c2ecf20Sopenharmony_ci}
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci/*
1188c2ecf20Sopenharmony_ci * Read hardware ECC value and pack into three bytes
1198c2ecf20Sopenharmony_ci */
1208c2ecf20Sopenharmony_cistatic int nand_davinci_calculate_1bit(struct nand_chip *chip,
1218c2ecf20Sopenharmony_ci				       const u_char *dat, u_char *ecc_code)
1228c2ecf20Sopenharmony_ci{
1238c2ecf20Sopenharmony_ci	unsigned int ecc_val = nand_davinci_readecc_1bit(nand_to_mtd(chip));
1248c2ecf20Sopenharmony_ci	unsigned int ecc24 = (ecc_val & 0x0fff) | ((ecc_val & 0x0fff0000) >> 4);
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	/* invert so that erased block ecc is correct */
1278c2ecf20Sopenharmony_ci	ecc24 = ~ecc24;
1288c2ecf20Sopenharmony_ci	ecc_code[0] = (u_char)(ecc24);
1298c2ecf20Sopenharmony_ci	ecc_code[1] = (u_char)(ecc24 >> 8);
1308c2ecf20Sopenharmony_ci	ecc_code[2] = (u_char)(ecc24 >> 16);
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	return 0;
1338c2ecf20Sopenharmony_ci}
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_cistatic int nand_davinci_correct_1bit(struct nand_chip *chip, u_char *dat,
1368c2ecf20Sopenharmony_ci				     u_char *read_ecc, u_char *calc_ecc)
1378c2ecf20Sopenharmony_ci{
1388c2ecf20Sopenharmony_ci	uint32_t eccNand = read_ecc[0] | (read_ecc[1] << 8) |
1398c2ecf20Sopenharmony_ci					  (read_ecc[2] << 16);
1408c2ecf20Sopenharmony_ci	uint32_t eccCalc = calc_ecc[0] | (calc_ecc[1] << 8) |
1418c2ecf20Sopenharmony_ci					  (calc_ecc[2] << 16);
1428c2ecf20Sopenharmony_ci	uint32_t diff = eccCalc ^ eccNand;
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	if (diff) {
1458c2ecf20Sopenharmony_ci		if ((((diff >> 12) ^ diff) & 0xfff) == 0xfff) {
1468c2ecf20Sopenharmony_ci			/* Correctable error */
1478c2ecf20Sopenharmony_ci			if ((diff >> (12 + 3)) < chip->ecc.size) {
1488c2ecf20Sopenharmony_ci				dat[diff >> (12 + 3)] ^= BIT((diff >> 12) & 7);
1498c2ecf20Sopenharmony_ci				return 1;
1508c2ecf20Sopenharmony_ci			} else {
1518c2ecf20Sopenharmony_ci				return -EBADMSG;
1528c2ecf20Sopenharmony_ci			}
1538c2ecf20Sopenharmony_ci		} else if (!(diff & (diff - 1))) {
1548c2ecf20Sopenharmony_ci			/* Single bit ECC error in the ECC itself,
1558c2ecf20Sopenharmony_ci			 * nothing to fix */
1568c2ecf20Sopenharmony_ci			return 1;
1578c2ecf20Sopenharmony_ci		} else {
1588c2ecf20Sopenharmony_ci			/* Uncorrectable error */
1598c2ecf20Sopenharmony_ci			return -EBADMSG;
1608c2ecf20Sopenharmony_ci		}
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	}
1638c2ecf20Sopenharmony_ci	return 0;
1648c2ecf20Sopenharmony_ci}
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci/*----------------------------------------------------------------------*/
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci/*
1698c2ecf20Sopenharmony_ci * 4-bit hardware ECC ... context maintained over entire AEMIF
1708c2ecf20Sopenharmony_ci *
1718c2ecf20Sopenharmony_ci * This is a syndrome engine, but we avoid NAND_ECC_PLACEMENT_INTERLEAVED
1728c2ecf20Sopenharmony_ci * since that forces use of a problematic "infix OOB" layout.
1738c2ecf20Sopenharmony_ci * Among other things, it trashes manufacturer bad block markers.
1748c2ecf20Sopenharmony_ci * Also, and specific to this hardware, it ECC-protects the "prepad"
1758c2ecf20Sopenharmony_ci * in the OOB ... while having ECC protection for parts of OOB would
1768c2ecf20Sopenharmony_ci * seem useful, the current MTD stack sometimes wants to update the
1778c2ecf20Sopenharmony_ci * OOB without recomputing ECC.
1788c2ecf20Sopenharmony_ci */
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_cistatic void nand_davinci_hwctl_4bit(struct nand_chip *chip, int mode)
1818c2ecf20Sopenharmony_ci{
1828c2ecf20Sopenharmony_ci	struct davinci_nand_info *info = to_davinci_nand(nand_to_mtd(chip));
1838c2ecf20Sopenharmony_ci	unsigned long flags;
1848c2ecf20Sopenharmony_ci	u32 val;
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	/* Reset ECC hardware */
1878c2ecf20Sopenharmony_ci	davinci_nand_readl(info, NAND_4BIT_ECC1_OFFSET);
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	spin_lock_irqsave(&davinci_nand_lock, flags);
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	/* Start 4-bit ECC calculation for read/write */
1928c2ecf20Sopenharmony_ci	val = davinci_nand_readl(info, NANDFCR_OFFSET);
1938c2ecf20Sopenharmony_ci	val &= ~(0x03 << 4);
1948c2ecf20Sopenharmony_ci	val |= (info->core_chipsel << 4) | BIT(12);
1958c2ecf20Sopenharmony_ci	davinci_nand_writel(info, NANDFCR_OFFSET, val);
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	info->is_readmode = (mode == NAND_ECC_READ);
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&davinci_nand_lock, flags);
2008c2ecf20Sopenharmony_ci}
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci/* Read raw ECC code after writing to NAND. */
2038c2ecf20Sopenharmony_cistatic void
2048c2ecf20Sopenharmony_cinand_davinci_readecc_4bit(struct davinci_nand_info *info, u32 code[4])
2058c2ecf20Sopenharmony_ci{
2068c2ecf20Sopenharmony_ci	const u32 mask = 0x03ff03ff;
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	code[0] = davinci_nand_readl(info, NAND_4BIT_ECC1_OFFSET) & mask;
2098c2ecf20Sopenharmony_ci	code[1] = davinci_nand_readl(info, NAND_4BIT_ECC2_OFFSET) & mask;
2108c2ecf20Sopenharmony_ci	code[2] = davinci_nand_readl(info, NAND_4BIT_ECC3_OFFSET) & mask;
2118c2ecf20Sopenharmony_ci	code[3] = davinci_nand_readl(info, NAND_4BIT_ECC4_OFFSET) & mask;
2128c2ecf20Sopenharmony_ci}
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci/* Terminate read ECC; or return ECC (as bytes) of data written to NAND. */
2158c2ecf20Sopenharmony_cistatic int nand_davinci_calculate_4bit(struct nand_chip *chip,
2168c2ecf20Sopenharmony_ci				       const u_char *dat, u_char *ecc_code)
2178c2ecf20Sopenharmony_ci{
2188c2ecf20Sopenharmony_ci	struct davinci_nand_info *info = to_davinci_nand(nand_to_mtd(chip));
2198c2ecf20Sopenharmony_ci	u32 raw_ecc[4], *p;
2208c2ecf20Sopenharmony_ci	unsigned i;
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	/* After a read, terminate ECC calculation by a dummy read
2238c2ecf20Sopenharmony_ci	 * of some 4-bit ECC register.  ECC covers everything that
2248c2ecf20Sopenharmony_ci	 * was read; correct() just uses the hardware state, so
2258c2ecf20Sopenharmony_ci	 * ecc_code is not needed.
2268c2ecf20Sopenharmony_ci	 */
2278c2ecf20Sopenharmony_ci	if (info->is_readmode) {
2288c2ecf20Sopenharmony_ci		davinci_nand_readl(info, NAND_4BIT_ECC1_OFFSET);
2298c2ecf20Sopenharmony_ci		return 0;
2308c2ecf20Sopenharmony_ci	}
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	/* Pack eight raw 10-bit ecc values into ten bytes, making
2338c2ecf20Sopenharmony_ci	 * two passes which each convert four values (in upper and
2348c2ecf20Sopenharmony_ci	 * lower halves of two 32-bit words) into five bytes.  The
2358c2ecf20Sopenharmony_ci	 * ROM boot loader uses this same packing scheme.
2368c2ecf20Sopenharmony_ci	 */
2378c2ecf20Sopenharmony_ci	nand_davinci_readecc_4bit(info, raw_ecc);
2388c2ecf20Sopenharmony_ci	for (i = 0, p = raw_ecc; i < 2; i++, p += 2) {
2398c2ecf20Sopenharmony_ci		*ecc_code++ =   p[0]        & 0xff;
2408c2ecf20Sopenharmony_ci		*ecc_code++ = ((p[0] >>  8) & 0x03) | ((p[0] >> 14) & 0xfc);
2418c2ecf20Sopenharmony_ci		*ecc_code++ = ((p[0] >> 22) & 0x0f) | ((p[1] <<  4) & 0xf0);
2428c2ecf20Sopenharmony_ci		*ecc_code++ = ((p[1] >>  4) & 0x3f) | ((p[1] >> 10) & 0xc0);
2438c2ecf20Sopenharmony_ci		*ecc_code++ =  (p[1] >> 18) & 0xff;
2448c2ecf20Sopenharmony_ci	}
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	return 0;
2478c2ecf20Sopenharmony_ci}
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci/* Correct up to 4 bits in data we just read, using state left in the
2508c2ecf20Sopenharmony_ci * hardware plus the ecc_code computed when it was first written.
2518c2ecf20Sopenharmony_ci */
2528c2ecf20Sopenharmony_cistatic int nand_davinci_correct_4bit(struct nand_chip *chip, u_char *data,
2538c2ecf20Sopenharmony_ci				     u_char *ecc_code, u_char *null)
2548c2ecf20Sopenharmony_ci{
2558c2ecf20Sopenharmony_ci	int i;
2568c2ecf20Sopenharmony_ci	struct davinci_nand_info *info = to_davinci_nand(nand_to_mtd(chip));
2578c2ecf20Sopenharmony_ci	unsigned short ecc10[8];
2588c2ecf20Sopenharmony_ci	unsigned short *ecc16;
2598c2ecf20Sopenharmony_ci	u32 syndrome[4];
2608c2ecf20Sopenharmony_ci	u32 ecc_state;
2618c2ecf20Sopenharmony_ci	unsigned num_errors, corrected;
2628c2ecf20Sopenharmony_ci	unsigned long timeo;
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	/* Unpack ten bytes into eight 10 bit values.  We know we're
2658c2ecf20Sopenharmony_ci	 * little-endian, and use type punning for less shifting/masking.
2668c2ecf20Sopenharmony_ci	 */
2678c2ecf20Sopenharmony_ci	if (WARN_ON(0x01 & (uintptr_t)ecc_code))
2688c2ecf20Sopenharmony_ci		return -EINVAL;
2698c2ecf20Sopenharmony_ci	ecc16 = (unsigned short *)ecc_code;
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	ecc10[0] =  (ecc16[0] >>  0) & 0x3ff;
2728c2ecf20Sopenharmony_ci	ecc10[1] = ((ecc16[0] >> 10) & 0x3f) | ((ecc16[1] << 6) & 0x3c0);
2738c2ecf20Sopenharmony_ci	ecc10[2] =  (ecc16[1] >>  4) & 0x3ff;
2748c2ecf20Sopenharmony_ci	ecc10[3] = ((ecc16[1] >> 14) & 0x3)  | ((ecc16[2] << 2) & 0x3fc);
2758c2ecf20Sopenharmony_ci	ecc10[4] =  (ecc16[2] >>  8)         | ((ecc16[3] << 8) & 0x300);
2768c2ecf20Sopenharmony_ci	ecc10[5] =  (ecc16[3] >>  2) & 0x3ff;
2778c2ecf20Sopenharmony_ci	ecc10[6] = ((ecc16[3] >> 12) & 0xf)  | ((ecc16[4] << 4) & 0x3f0);
2788c2ecf20Sopenharmony_ci	ecc10[7] =  (ecc16[4] >>  6) & 0x3ff;
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	/* Tell ECC controller about the expected ECC codes. */
2818c2ecf20Sopenharmony_ci	for (i = 7; i >= 0; i--)
2828c2ecf20Sopenharmony_ci		davinci_nand_writel(info, NAND_4BIT_ECC_LOAD_OFFSET, ecc10[i]);
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	/* Allow time for syndrome calculation ... then read it.
2858c2ecf20Sopenharmony_ci	 * A syndrome of all zeroes 0 means no detected errors.
2868c2ecf20Sopenharmony_ci	 */
2878c2ecf20Sopenharmony_ci	davinci_nand_readl(info, NANDFSR_OFFSET);
2888c2ecf20Sopenharmony_ci	nand_davinci_readecc_4bit(info, syndrome);
2898c2ecf20Sopenharmony_ci	if (!(syndrome[0] | syndrome[1] | syndrome[2] | syndrome[3]))
2908c2ecf20Sopenharmony_ci		return 0;
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci	/*
2938c2ecf20Sopenharmony_ci	 * Clear any previous address calculation by doing a dummy read of an
2948c2ecf20Sopenharmony_ci	 * error address register.
2958c2ecf20Sopenharmony_ci	 */
2968c2ecf20Sopenharmony_ci	davinci_nand_readl(info, NAND_ERR_ADD1_OFFSET);
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	/* Start address calculation, and wait for it to complete.
2998c2ecf20Sopenharmony_ci	 * We _could_ start reading more data while this is working,
3008c2ecf20Sopenharmony_ci	 * to speed up the overall page read.
3018c2ecf20Sopenharmony_ci	 */
3028c2ecf20Sopenharmony_ci	davinci_nand_writel(info, NANDFCR_OFFSET,
3038c2ecf20Sopenharmony_ci			davinci_nand_readl(info, NANDFCR_OFFSET) | BIT(13));
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	/*
3068c2ecf20Sopenharmony_ci	 * ECC_STATE field reads 0x3 (Error correction complete) immediately
3078c2ecf20Sopenharmony_ci	 * after setting the 4BITECC_ADD_CALC_START bit. So if you immediately
3088c2ecf20Sopenharmony_ci	 * begin trying to poll for the state, you may fall right out of your
3098c2ecf20Sopenharmony_ci	 * loop without any of the correction calculations having taken place.
3108c2ecf20Sopenharmony_ci	 * The recommendation from the hardware team is to initially delay as
3118c2ecf20Sopenharmony_ci	 * long as ECC_STATE reads less than 4. After that, ECC HW has entered
3128c2ecf20Sopenharmony_ci	 * correction state.
3138c2ecf20Sopenharmony_ci	 */
3148c2ecf20Sopenharmony_ci	timeo = jiffies + usecs_to_jiffies(100);
3158c2ecf20Sopenharmony_ci	do {
3168c2ecf20Sopenharmony_ci		ecc_state = (davinci_nand_readl(info,
3178c2ecf20Sopenharmony_ci				NANDFSR_OFFSET) >> 8) & 0x0f;
3188c2ecf20Sopenharmony_ci		cpu_relax();
3198c2ecf20Sopenharmony_ci	} while ((ecc_state < 4) && time_before(jiffies, timeo));
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	for (;;) {
3228c2ecf20Sopenharmony_ci		u32	fsr = davinci_nand_readl(info, NANDFSR_OFFSET);
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci		switch ((fsr >> 8) & 0x0f) {
3258c2ecf20Sopenharmony_ci		case 0:		/* no error, should not happen */
3268c2ecf20Sopenharmony_ci			davinci_nand_readl(info, NAND_ERR_ERRVAL1_OFFSET);
3278c2ecf20Sopenharmony_ci			return 0;
3288c2ecf20Sopenharmony_ci		case 1:		/* five or more errors detected */
3298c2ecf20Sopenharmony_ci			davinci_nand_readl(info, NAND_ERR_ERRVAL1_OFFSET);
3308c2ecf20Sopenharmony_ci			return -EBADMSG;
3318c2ecf20Sopenharmony_ci		case 2:		/* error addresses computed */
3328c2ecf20Sopenharmony_ci		case 3:
3338c2ecf20Sopenharmony_ci			num_errors = 1 + ((fsr >> 16) & 0x03);
3348c2ecf20Sopenharmony_ci			goto correct;
3358c2ecf20Sopenharmony_ci		default:	/* still working on it */
3368c2ecf20Sopenharmony_ci			cpu_relax();
3378c2ecf20Sopenharmony_ci			continue;
3388c2ecf20Sopenharmony_ci		}
3398c2ecf20Sopenharmony_ci	}
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_cicorrect:
3428c2ecf20Sopenharmony_ci	/* correct each error */
3438c2ecf20Sopenharmony_ci	for (i = 0, corrected = 0; i < num_errors; i++) {
3448c2ecf20Sopenharmony_ci		int error_address, error_value;
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci		if (i > 1) {
3478c2ecf20Sopenharmony_ci			error_address = davinci_nand_readl(info,
3488c2ecf20Sopenharmony_ci						NAND_ERR_ADD2_OFFSET);
3498c2ecf20Sopenharmony_ci			error_value = davinci_nand_readl(info,
3508c2ecf20Sopenharmony_ci						NAND_ERR_ERRVAL2_OFFSET);
3518c2ecf20Sopenharmony_ci		} else {
3528c2ecf20Sopenharmony_ci			error_address = davinci_nand_readl(info,
3538c2ecf20Sopenharmony_ci						NAND_ERR_ADD1_OFFSET);
3548c2ecf20Sopenharmony_ci			error_value = davinci_nand_readl(info,
3558c2ecf20Sopenharmony_ci						NAND_ERR_ERRVAL1_OFFSET);
3568c2ecf20Sopenharmony_ci		}
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci		if (i & 1) {
3598c2ecf20Sopenharmony_ci			error_address >>= 16;
3608c2ecf20Sopenharmony_ci			error_value >>= 16;
3618c2ecf20Sopenharmony_ci		}
3628c2ecf20Sopenharmony_ci		error_address &= 0x3ff;
3638c2ecf20Sopenharmony_ci		error_address = (512 + 7) - error_address;
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci		if (error_address < 512) {
3668c2ecf20Sopenharmony_ci			data[error_address] ^= error_value;
3678c2ecf20Sopenharmony_ci			corrected++;
3688c2ecf20Sopenharmony_ci		}
3698c2ecf20Sopenharmony_ci	}
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci	return corrected;
3728c2ecf20Sopenharmony_ci}
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci/**
3758c2ecf20Sopenharmony_ci * nand_davinci_read_page_hwecc_oob_first - Hardware ECC page read with ECC
3768c2ecf20Sopenharmony_ci *                                          data read from OOB area
3778c2ecf20Sopenharmony_ci * @chip: nand chip info structure
3788c2ecf20Sopenharmony_ci * @buf: buffer to store read data
3798c2ecf20Sopenharmony_ci * @oob_required: caller requires OOB data read to chip->oob_poi
3808c2ecf20Sopenharmony_ci * @page: page number to read
3818c2ecf20Sopenharmony_ci *
3828c2ecf20Sopenharmony_ci * Hardware ECC for large page chips, which requires the ECC data to be
3838c2ecf20Sopenharmony_ci * extracted from the OOB before the actual data is read.
3848c2ecf20Sopenharmony_ci */
3858c2ecf20Sopenharmony_cistatic int nand_davinci_read_page_hwecc_oob_first(struct nand_chip *chip,
3868c2ecf20Sopenharmony_ci						  uint8_t *buf,
3878c2ecf20Sopenharmony_ci						  int oob_required, int page)
3888c2ecf20Sopenharmony_ci{
3898c2ecf20Sopenharmony_ci	struct mtd_info *mtd = nand_to_mtd(chip);
3908c2ecf20Sopenharmony_ci	int i, eccsize = chip->ecc.size, ret;
3918c2ecf20Sopenharmony_ci	int eccbytes = chip->ecc.bytes;
3928c2ecf20Sopenharmony_ci	int eccsteps = chip->ecc.steps;
3938c2ecf20Sopenharmony_ci	uint8_t *p = buf;
3948c2ecf20Sopenharmony_ci	uint8_t *ecc_code = chip->ecc.code_buf;
3958c2ecf20Sopenharmony_ci	unsigned int max_bitflips = 0;
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci	/* Read the OOB area first */
3988c2ecf20Sopenharmony_ci	ret = nand_read_oob_op(chip, page, 0, chip->oob_poi, mtd->oobsize);
3998c2ecf20Sopenharmony_ci	if (ret)
4008c2ecf20Sopenharmony_ci		return ret;
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci	/* Move read cursor to start of page */
4038c2ecf20Sopenharmony_ci	ret = nand_change_read_column_op(chip, 0, NULL, 0, false);
4048c2ecf20Sopenharmony_ci	if (ret)
4058c2ecf20Sopenharmony_ci		return ret;
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci	ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0,
4088c2ecf20Sopenharmony_ci					 chip->ecc.total);
4098c2ecf20Sopenharmony_ci	if (ret)
4108c2ecf20Sopenharmony_ci		return ret;
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
4138c2ecf20Sopenharmony_ci		int stat;
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci		chip->ecc.hwctl(chip, NAND_ECC_READ);
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci		ret = nand_read_data_op(chip, p, eccsize, false, false);
4188c2ecf20Sopenharmony_ci		if (ret)
4198c2ecf20Sopenharmony_ci			return ret;
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci		stat = chip->ecc.correct(chip, p, &ecc_code[i], NULL);
4228c2ecf20Sopenharmony_ci		if (stat == -EBADMSG &&
4238c2ecf20Sopenharmony_ci		    (chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) {
4248c2ecf20Sopenharmony_ci			/* check for empty pages with bitflips */
4258c2ecf20Sopenharmony_ci			stat = nand_check_erased_ecc_chunk(p, eccsize,
4268c2ecf20Sopenharmony_ci							   &ecc_code[i],
4278c2ecf20Sopenharmony_ci							   eccbytes, NULL, 0,
4288c2ecf20Sopenharmony_ci							   chip->ecc.strength);
4298c2ecf20Sopenharmony_ci		}
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci		if (stat < 0) {
4328c2ecf20Sopenharmony_ci			mtd->ecc_stats.failed++;
4338c2ecf20Sopenharmony_ci		} else {
4348c2ecf20Sopenharmony_ci			mtd->ecc_stats.corrected += stat;
4358c2ecf20Sopenharmony_ci			max_bitflips = max_t(unsigned int, max_bitflips, stat);
4368c2ecf20Sopenharmony_ci		}
4378c2ecf20Sopenharmony_ci	}
4388c2ecf20Sopenharmony_ci	return max_bitflips;
4398c2ecf20Sopenharmony_ci}
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci/*----------------------------------------------------------------------*/
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci/* An ECC layout for using 4-bit ECC with small-page flash, storing
4448c2ecf20Sopenharmony_ci * ten ECC bytes plus the manufacturer's bad block marker byte, and
4458c2ecf20Sopenharmony_ci * and not overlapping the default BBT markers.
4468c2ecf20Sopenharmony_ci */
4478c2ecf20Sopenharmony_cistatic int hwecc4_ooblayout_small_ecc(struct mtd_info *mtd, int section,
4488c2ecf20Sopenharmony_ci				      struct mtd_oob_region *oobregion)
4498c2ecf20Sopenharmony_ci{
4508c2ecf20Sopenharmony_ci	if (section > 2)
4518c2ecf20Sopenharmony_ci		return -ERANGE;
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci	if (!section) {
4548c2ecf20Sopenharmony_ci		oobregion->offset = 0;
4558c2ecf20Sopenharmony_ci		oobregion->length = 5;
4568c2ecf20Sopenharmony_ci	} else if (section == 1) {
4578c2ecf20Sopenharmony_ci		oobregion->offset = 6;
4588c2ecf20Sopenharmony_ci		oobregion->length = 2;
4598c2ecf20Sopenharmony_ci	} else {
4608c2ecf20Sopenharmony_ci		oobregion->offset = 13;
4618c2ecf20Sopenharmony_ci		oobregion->length = 3;
4628c2ecf20Sopenharmony_ci	}
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci	return 0;
4658c2ecf20Sopenharmony_ci}
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_cistatic int hwecc4_ooblayout_small_free(struct mtd_info *mtd, int section,
4688c2ecf20Sopenharmony_ci				       struct mtd_oob_region *oobregion)
4698c2ecf20Sopenharmony_ci{
4708c2ecf20Sopenharmony_ci	if (section > 1)
4718c2ecf20Sopenharmony_ci		return -ERANGE;
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci	if (!section) {
4748c2ecf20Sopenharmony_ci		oobregion->offset = 8;
4758c2ecf20Sopenharmony_ci		oobregion->length = 5;
4768c2ecf20Sopenharmony_ci	} else {
4778c2ecf20Sopenharmony_ci		oobregion->offset = 16;
4788c2ecf20Sopenharmony_ci		oobregion->length = mtd->oobsize - 16;
4798c2ecf20Sopenharmony_ci	}
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci	return 0;
4828c2ecf20Sopenharmony_ci}
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_cistatic const struct mtd_ooblayout_ops hwecc4_small_ooblayout_ops = {
4858c2ecf20Sopenharmony_ci	.ecc = hwecc4_ooblayout_small_ecc,
4868c2ecf20Sopenharmony_ci	.free = hwecc4_ooblayout_small_free,
4878c2ecf20Sopenharmony_ci};
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci#if defined(CONFIG_OF)
4908c2ecf20Sopenharmony_cistatic const struct of_device_id davinci_nand_of_match[] = {
4918c2ecf20Sopenharmony_ci	{.compatible = "ti,davinci-nand", },
4928c2ecf20Sopenharmony_ci	{.compatible = "ti,keystone-nand", },
4938c2ecf20Sopenharmony_ci	{},
4948c2ecf20Sopenharmony_ci};
4958c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, davinci_nand_of_match);
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_cistatic struct davinci_nand_pdata
4988c2ecf20Sopenharmony_ci	*nand_davinci_get_pdata(struct platform_device *pdev)
4998c2ecf20Sopenharmony_ci{
5008c2ecf20Sopenharmony_ci	if (!dev_get_platdata(&pdev->dev) && pdev->dev.of_node) {
5018c2ecf20Sopenharmony_ci		struct davinci_nand_pdata *pdata;
5028c2ecf20Sopenharmony_ci		const char *mode;
5038c2ecf20Sopenharmony_ci		u32 prop;
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci		pdata =  devm_kzalloc(&pdev->dev,
5068c2ecf20Sopenharmony_ci				sizeof(struct davinci_nand_pdata),
5078c2ecf20Sopenharmony_ci				GFP_KERNEL);
5088c2ecf20Sopenharmony_ci		pdev->dev.platform_data = pdata;
5098c2ecf20Sopenharmony_ci		if (!pdata)
5108c2ecf20Sopenharmony_ci			return ERR_PTR(-ENOMEM);
5118c2ecf20Sopenharmony_ci		if (!of_property_read_u32(pdev->dev.of_node,
5128c2ecf20Sopenharmony_ci			"ti,davinci-chipselect", &prop))
5138c2ecf20Sopenharmony_ci			pdata->core_chipsel = prop;
5148c2ecf20Sopenharmony_ci		else
5158c2ecf20Sopenharmony_ci			return ERR_PTR(-EINVAL);
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci		if (!of_property_read_u32(pdev->dev.of_node,
5188c2ecf20Sopenharmony_ci			"ti,davinci-mask-ale", &prop))
5198c2ecf20Sopenharmony_ci			pdata->mask_ale = prop;
5208c2ecf20Sopenharmony_ci		if (!of_property_read_u32(pdev->dev.of_node,
5218c2ecf20Sopenharmony_ci			"ti,davinci-mask-cle", &prop))
5228c2ecf20Sopenharmony_ci			pdata->mask_cle = prop;
5238c2ecf20Sopenharmony_ci		if (!of_property_read_u32(pdev->dev.of_node,
5248c2ecf20Sopenharmony_ci			"ti,davinci-mask-chipsel", &prop))
5258c2ecf20Sopenharmony_ci			pdata->mask_chipsel = prop;
5268c2ecf20Sopenharmony_ci		if (!of_property_read_string(pdev->dev.of_node,
5278c2ecf20Sopenharmony_ci			"ti,davinci-ecc-mode", &mode)) {
5288c2ecf20Sopenharmony_ci			if (!strncmp("none", mode, 4))
5298c2ecf20Sopenharmony_ci				pdata->engine_type = NAND_ECC_ENGINE_TYPE_NONE;
5308c2ecf20Sopenharmony_ci			if (!strncmp("soft", mode, 4))
5318c2ecf20Sopenharmony_ci				pdata->engine_type = NAND_ECC_ENGINE_TYPE_SOFT;
5328c2ecf20Sopenharmony_ci			if (!strncmp("hw", mode, 2))
5338c2ecf20Sopenharmony_ci				pdata->engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST;
5348c2ecf20Sopenharmony_ci		}
5358c2ecf20Sopenharmony_ci		if (!of_property_read_u32(pdev->dev.of_node,
5368c2ecf20Sopenharmony_ci			"ti,davinci-ecc-bits", &prop))
5378c2ecf20Sopenharmony_ci			pdata->ecc_bits = prop;
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_ci		if (!of_property_read_u32(pdev->dev.of_node,
5408c2ecf20Sopenharmony_ci			"ti,davinci-nand-buswidth", &prop) && prop == 16)
5418c2ecf20Sopenharmony_ci			pdata->options |= NAND_BUSWIDTH_16;
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci		if (of_property_read_bool(pdev->dev.of_node,
5448c2ecf20Sopenharmony_ci			"ti,davinci-nand-use-bbt"))
5458c2ecf20Sopenharmony_ci			pdata->bbt_options = NAND_BBT_USE_FLASH;
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_ci		/*
5488c2ecf20Sopenharmony_ci		 * Since kernel v4.8, this driver has been fixed to enable
5498c2ecf20Sopenharmony_ci		 * use of 4-bit hardware ECC with subpages and verified on
5508c2ecf20Sopenharmony_ci		 * TI's keystone EVMs (K2L, K2HK and K2E).
5518c2ecf20Sopenharmony_ci		 * However, in the interest of not breaking systems using
5528c2ecf20Sopenharmony_ci		 * existing UBI partitions, sub-page writes are not being
5538c2ecf20Sopenharmony_ci		 * (re)enabled. If you want to use subpage writes on Keystone
5548c2ecf20Sopenharmony_ci		 * platforms (i.e. do not have any existing UBI partitions),
5558c2ecf20Sopenharmony_ci		 * then use "ti,davinci-nand" as the compatible in your
5568c2ecf20Sopenharmony_ci		 * device-tree file.
5578c2ecf20Sopenharmony_ci		 */
5588c2ecf20Sopenharmony_ci		if (of_device_is_compatible(pdev->dev.of_node,
5598c2ecf20Sopenharmony_ci					    "ti,keystone-nand")) {
5608c2ecf20Sopenharmony_ci			pdata->options |= NAND_NO_SUBPAGE_WRITE;
5618c2ecf20Sopenharmony_ci		}
5628c2ecf20Sopenharmony_ci	}
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_ci	return dev_get_platdata(&pdev->dev);
5658c2ecf20Sopenharmony_ci}
5668c2ecf20Sopenharmony_ci#else
5678c2ecf20Sopenharmony_cistatic struct davinci_nand_pdata
5688c2ecf20Sopenharmony_ci	*nand_davinci_get_pdata(struct platform_device *pdev)
5698c2ecf20Sopenharmony_ci{
5708c2ecf20Sopenharmony_ci	return dev_get_platdata(&pdev->dev);
5718c2ecf20Sopenharmony_ci}
5728c2ecf20Sopenharmony_ci#endif
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_cistatic int davinci_nand_attach_chip(struct nand_chip *chip)
5758c2ecf20Sopenharmony_ci{
5768c2ecf20Sopenharmony_ci	struct mtd_info *mtd = nand_to_mtd(chip);
5778c2ecf20Sopenharmony_ci	struct davinci_nand_info *info = to_davinci_nand(mtd);
5788c2ecf20Sopenharmony_ci	struct davinci_nand_pdata *pdata = nand_davinci_get_pdata(info->pdev);
5798c2ecf20Sopenharmony_ci	int ret = 0;
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci	if (IS_ERR(pdata))
5828c2ecf20Sopenharmony_ci		return PTR_ERR(pdata);
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_ci	/* Use board-specific ECC config */
5858c2ecf20Sopenharmony_ci	info->chip.ecc.engine_type = pdata->engine_type;
5868c2ecf20Sopenharmony_ci	info->chip.ecc.placement = pdata->ecc_placement;
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci	switch (info->chip.ecc.engine_type) {
5898c2ecf20Sopenharmony_ci	case NAND_ECC_ENGINE_TYPE_NONE:
5908c2ecf20Sopenharmony_ci		pdata->ecc_bits = 0;
5918c2ecf20Sopenharmony_ci		break;
5928c2ecf20Sopenharmony_ci	case NAND_ECC_ENGINE_TYPE_SOFT:
5938c2ecf20Sopenharmony_ci		pdata->ecc_bits = 0;
5948c2ecf20Sopenharmony_ci		/*
5958c2ecf20Sopenharmony_ci		 * This driver expects Hamming based ECC when engine_type is set
5968c2ecf20Sopenharmony_ci		 * to NAND_ECC_ENGINE_TYPE_SOFT. Force ecc.algo to
5978c2ecf20Sopenharmony_ci		 * NAND_ECC_ALGO_HAMMING to avoid adding an extra ->ecc_algo
5988c2ecf20Sopenharmony_ci		 * field to davinci_nand_pdata.
5998c2ecf20Sopenharmony_ci		 */
6008c2ecf20Sopenharmony_ci		info->chip.ecc.algo = NAND_ECC_ALGO_HAMMING;
6018c2ecf20Sopenharmony_ci		break;
6028c2ecf20Sopenharmony_ci	case NAND_ECC_ENGINE_TYPE_ON_HOST:
6038c2ecf20Sopenharmony_ci		if (pdata->ecc_bits == 4) {
6048c2ecf20Sopenharmony_ci			int chunks = mtd->writesize / 512;
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci			if (!chunks || mtd->oobsize < 16) {
6078c2ecf20Sopenharmony_ci				dev_dbg(&info->pdev->dev, "too small\n");
6088c2ecf20Sopenharmony_ci				return -EINVAL;
6098c2ecf20Sopenharmony_ci			}
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_ci			/*
6128c2ecf20Sopenharmony_ci			 * No sanity checks:  CPUs must support this,
6138c2ecf20Sopenharmony_ci			 * and the chips may not use NAND_BUSWIDTH_16.
6148c2ecf20Sopenharmony_ci			 */
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_ci			/* No sharing 4-bit hardware between chipselects yet */
6178c2ecf20Sopenharmony_ci			spin_lock_irq(&davinci_nand_lock);
6188c2ecf20Sopenharmony_ci			if (ecc4_busy)
6198c2ecf20Sopenharmony_ci				ret = -EBUSY;
6208c2ecf20Sopenharmony_ci			else
6218c2ecf20Sopenharmony_ci				ecc4_busy = true;
6228c2ecf20Sopenharmony_ci			spin_unlock_irq(&davinci_nand_lock);
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_ci			if (ret == -EBUSY)
6258c2ecf20Sopenharmony_ci				return ret;
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_ci			info->chip.ecc.calculate = nand_davinci_calculate_4bit;
6288c2ecf20Sopenharmony_ci			info->chip.ecc.correct = nand_davinci_correct_4bit;
6298c2ecf20Sopenharmony_ci			info->chip.ecc.hwctl = nand_davinci_hwctl_4bit;
6308c2ecf20Sopenharmony_ci			info->chip.ecc.bytes = 10;
6318c2ecf20Sopenharmony_ci			info->chip.ecc.options = NAND_ECC_GENERIC_ERASED_CHECK;
6328c2ecf20Sopenharmony_ci			info->chip.ecc.algo = NAND_ECC_ALGO_BCH;
6338c2ecf20Sopenharmony_ci
6348c2ecf20Sopenharmony_ci			/*
6358c2ecf20Sopenharmony_ci			 * Update ECC layout if needed ... for 1-bit HW ECC, the
6368c2ecf20Sopenharmony_ci			 * default is OK, but it allocates 6 bytes when only 3
6378c2ecf20Sopenharmony_ci			 * are needed (for each 512 bytes). For 4-bit HW ECC,
6388c2ecf20Sopenharmony_ci			 * the default is not usable: 10 bytes needed, not 6.
6398c2ecf20Sopenharmony_ci			 *
6408c2ecf20Sopenharmony_ci			 * For small page chips, preserve the manufacturer's
6418c2ecf20Sopenharmony_ci			 * badblock marking data ... and make sure a flash BBT
6428c2ecf20Sopenharmony_ci			 * table marker fits in the free bytes.
6438c2ecf20Sopenharmony_ci			 */
6448c2ecf20Sopenharmony_ci			if (chunks == 1) {
6458c2ecf20Sopenharmony_ci				mtd_set_ooblayout(mtd,
6468c2ecf20Sopenharmony_ci						  &hwecc4_small_ooblayout_ops);
6478c2ecf20Sopenharmony_ci			} else if (chunks == 4 || chunks == 8) {
6488c2ecf20Sopenharmony_ci				mtd_set_ooblayout(mtd,
6498c2ecf20Sopenharmony_ci						  nand_get_large_page_ooblayout());
6508c2ecf20Sopenharmony_ci				info->chip.ecc.read_page = nand_davinci_read_page_hwecc_oob_first;
6518c2ecf20Sopenharmony_ci			} else {
6528c2ecf20Sopenharmony_ci				return -EIO;
6538c2ecf20Sopenharmony_ci			}
6548c2ecf20Sopenharmony_ci		} else {
6558c2ecf20Sopenharmony_ci			/* 1bit ecc hamming */
6568c2ecf20Sopenharmony_ci			info->chip.ecc.calculate = nand_davinci_calculate_1bit;
6578c2ecf20Sopenharmony_ci			info->chip.ecc.correct = nand_davinci_correct_1bit;
6588c2ecf20Sopenharmony_ci			info->chip.ecc.hwctl = nand_davinci_hwctl_1bit;
6598c2ecf20Sopenharmony_ci			info->chip.ecc.bytes = 3;
6608c2ecf20Sopenharmony_ci			info->chip.ecc.algo = NAND_ECC_ALGO_HAMMING;
6618c2ecf20Sopenharmony_ci		}
6628c2ecf20Sopenharmony_ci		info->chip.ecc.size = 512;
6638c2ecf20Sopenharmony_ci		info->chip.ecc.strength = pdata->ecc_bits;
6648c2ecf20Sopenharmony_ci		break;
6658c2ecf20Sopenharmony_ci	default:
6668c2ecf20Sopenharmony_ci		return -EINVAL;
6678c2ecf20Sopenharmony_ci	}
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_ci	return ret;
6708c2ecf20Sopenharmony_ci}
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_cistatic void nand_davinci_data_in(struct davinci_nand_info *info, void *buf,
6738c2ecf20Sopenharmony_ci				 unsigned int len, bool force_8bit)
6748c2ecf20Sopenharmony_ci{
6758c2ecf20Sopenharmony_ci	u32 alignment = ((uintptr_t)buf | len) & 3;
6768c2ecf20Sopenharmony_ci
6778c2ecf20Sopenharmony_ci	if (force_8bit || (alignment & 1))
6788c2ecf20Sopenharmony_ci		ioread8_rep(info->current_cs, buf, len);
6798c2ecf20Sopenharmony_ci	else if (alignment & 3)
6808c2ecf20Sopenharmony_ci		ioread16_rep(info->current_cs, buf, len >> 1);
6818c2ecf20Sopenharmony_ci	else
6828c2ecf20Sopenharmony_ci		ioread32_rep(info->current_cs, buf, len >> 2);
6838c2ecf20Sopenharmony_ci}
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_cistatic void nand_davinci_data_out(struct davinci_nand_info *info,
6868c2ecf20Sopenharmony_ci				  const void *buf, unsigned int len,
6878c2ecf20Sopenharmony_ci				  bool force_8bit)
6888c2ecf20Sopenharmony_ci{
6898c2ecf20Sopenharmony_ci	u32 alignment = ((uintptr_t)buf | len) & 3;
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_ci	if (force_8bit || (alignment & 1))
6928c2ecf20Sopenharmony_ci		iowrite8_rep(info->current_cs, buf, len);
6938c2ecf20Sopenharmony_ci	else if (alignment & 3)
6948c2ecf20Sopenharmony_ci		iowrite16_rep(info->current_cs, buf, len >> 1);
6958c2ecf20Sopenharmony_ci	else
6968c2ecf20Sopenharmony_ci		iowrite32_rep(info->current_cs, buf, len >> 2);
6978c2ecf20Sopenharmony_ci}
6988c2ecf20Sopenharmony_ci
6998c2ecf20Sopenharmony_cistatic int davinci_nand_exec_instr(struct davinci_nand_info *info,
7008c2ecf20Sopenharmony_ci				   const struct nand_op_instr *instr)
7018c2ecf20Sopenharmony_ci{
7028c2ecf20Sopenharmony_ci	unsigned int i, timeout_us;
7038c2ecf20Sopenharmony_ci	u32 status;
7048c2ecf20Sopenharmony_ci	int ret;
7058c2ecf20Sopenharmony_ci
7068c2ecf20Sopenharmony_ci	switch (instr->type) {
7078c2ecf20Sopenharmony_ci	case NAND_OP_CMD_INSTR:
7088c2ecf20Sopenharmony_ci		iowrite8(instr->ctx.cmd.opcode,
7098c2ecf20Sopenharmony_ci			 info->current_cs + info->mask_cle);
7108c2ecf20Sopenharmony_ci		break;
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_ci	case NAND_OP_ADDR_INSTR:
7138c2ecf20Sopenharmony_ci		for (i = 0; i < instr->ctx.addr.naddrs; i++) {
7148c2ecf20Sopenharmony_ci			iowrite8(instr->ctx.addr.addrs[i],
7158c2ecf20Sopenharmony_ci				 info->current_cs + info->mask_ale);
7168c2ecf20Sopenharmony_ci		}
7178c2ecf20Sopenharmony_ci		break;
7188c2ecf20Sopenharmony_ci
7198c2ecf20Sopenharmony_ci	case NAND_OP_DATA_IN_INSTR:
7208c2ecf20Sopenharmony_ci		nand_davinci_data_in(info, instr->ctx.data.buf.in,
7218c2ecf20Sopenharmony_ci				     instr->ctx.data.len,
7228c2ecf20Sopenharmony_ci				     instr->ctx.data.force_8bit);
7238c2ecf20Sopenharmony_ci		break;
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ci	case NAND_OP_DATA_OUT_INSTR:
7268c2ecf20Sopenharmony_ci		nand_davinci_data_out(info, instr->ctx.data.buf.out,
7278c2ecf20Sopenharmony_ci				      instr->ctx.data.len,
7288c2ecf20Sopenharmony_ci				      instr->ctx.data.force_8bit);
7298c2ecf20Sopenharmony_ci		break;
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_ci	case NAND_OP_WAITRDY_INSTR:
7328c2ecf20Sopenharmony_ci		timeout_us = instr->ctx.waitrdy.timeout_ms * 1000;
7338c2ecf20Sopenharmony_ci		ret = readl_relaxed_poll_timeout(info->base + NANDFSR_OFFSET,
7348c2ecf20Sopenharmony_ci						 status, status & BIT(0), 100,
7358c2ecf20Sopenharmony_ci						 timeout_us);
7368c2ecf20Sopenharmony_ci		if (ret)
7378c2ecf20Sopenharmony_ci			return ret;
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_ci		break;
7408c2ecf20Sopenharmony_ci	}
7418c2ecf20Sopenharmony_ci
7428c2ecf20Sopenharmony_ci	if (instr->delay_ns)
7438c2ecf20Sopenharmony_ci		ndelay(instr->delay_ns);
7448c2ecf20Sopenharmony_ci
7458c2ecf20Sopenharmony_ci	return 0;
7468c2ecf20Sopenharmony_ci}
7478c2ecf20Sopenharmony_ci
7488c2ecf20Sopenharmony_cistatic int davinci_nand_exec_op(struct nand_chip *chip,
7498c2ecf20Sopenharmony_ci				const struct nand_operation *op,
7508c2ecf20Sopenharmony_ci				bool check_only)
7518c2ecf20Sopenharmony_ci{
7528c2ecf20Sopenharmony_ci	struct davinci_nand_info *info = to_davinci_nand(nand_to_mtd(chip));
7538c2ecf20Sopenharmony_ci	unsigned int i;
7548c2ecf20Sopenharmony_ci
7558c2ecf20Sopenharmony_ci	if (check_only)
7568c2ecf20Sopenharmony_ci		return 0;
7578c2ecf20Sopenharmony_ci
7588c2ecf20Sopenharmony_ci	info->current_cs = info->vaddr + (op->cs * info->mask_chipsel);
7598c2ecf20Sopenharmony_ci
7608c2ecf20Sopenharmony_ci	for (i = 0; i < op->ninstrs; i++) {
7618c2ecf20Sopenharmony_ci		int ret;
7628c2ecf20Sopenharmony_ci
7638c2ecf20Sopenharmony_ci		ret = davinci_nand_exec_instr(info, &op->instrs[i]);
7648c2ecf20Sopenharmony_ci		if (ret)
7658c2ecf20Sopenharmony_ci			return ret;
7668c2ecf20Sopenharmony_ci	}
7678c2ecf20Sopenharmony_ci
7688c2ecf20Sopenharmony_ci	return 0;
7698c2ecf20Sopenharmony_ci}
7708c2ecf20Sopenharmony_ci
7718c2ecf20Sopenharmony_cistatic const struct nand_controller_ops davinci_nand_controller_ops = {
7728c2ecf20Sopenharmony_ci	.attach_chip = davinci_nand_attach_chip,
7738c2ecf20Sopenharmony_ci	.exec_op = davinci_nand_exec_op,
7748c2ecf20Sopenharmony_ci};
7758c2ecf20Sopenharmony_ci
7768c2ecf20Sopenharmony_cistatic int nand_davinci_probe(struct platform_device *pdev)
7778c2ecf20Sopenharmony_ci{
7788c2ecf20Sopenharmony_ci	struct davinci_nand_pdata	*pdata;
7798c2ecf20Sopenharmony_ci	struct davinci_nand_info	*info;
7808c2ecf20Sopenharmony_ci	struct resource			*res1;
7818c2ecf20Sopenharmony_ci	struct resource			*res2;
7828c2ecf20Sopenharmony_ci	void __iomem			*vaddr;
7838c2ecf20Sopenharmony_ci	void __iomem			*base;
7848c2ecf20Sopenharmony_ci	int				ret;
7858c2ecf20Sopenharmony_ci	uint32_t			val;
7868c2ecf20Sopenharmony_ci	struct mtd_info			*mtd;
7878c2ecf20Sopenharmony_ci
7888c2ecf20Sopenharmony_ci	pdata = nand_davinci_get_pdata(pdev);
7898c2ecf20Sopenharmony_ci	if (IS_ERR(pdata))
7908c2ecf20Sopenharmony_ci		return PTR_ERR(pdata);
7918c2ecf20Sopenharmony_ci
7928c2ecf20Sopenharmony_ci	/* insist on board-specific configuration */
7938c2ecf20Sopenharmony_ci	if (!pdata)
7948c2ecf20Sopenharmony_ci		return -ENODEV;
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_ci	/* which external chipselect will we be managing? */
7978c2ecf20Sopenharmony_ci	if (pdata->core_chipsel < 0 || pdata->core_chipsel > 3)
7988c2ecf20Sopenharmony_ci		return -ENODEV;
7998c2ecf20Sopenharmony_ci
8008c2ecf20Sopenharmony_ci	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
8018c2ecf20Sopenharmony_ci	if (!info)
8028c2ecf20Sopenharmony_ci		return -ENOMEM;
8038c2ecf20Sopenharmony_ci
8048c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, info);
8058c2ecf20Sopenharmony_ci
8068c2ecf20Sopenharmony_ci	res1 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
8078c2ecf20Sopenharmony_ci	res2 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
8088c2ecf20Sopenharmony_ci	if (!res1 || !res2) {
8098c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "resource missing\n");
8108c2ecf20Sopenharmony_ci		return -EINVAL;
8118c2ecf20Sopenharmony_ci	}
8128c2ecf20Sopenharmony_ci
8138c2ecf20Sopenharmony_ci	vaddr = devm_ioremap_resource(&pdev->dev, res1);
8148c2ecf20Sopenharmony_ci	if (IS_ERR(vaddr))
8158c2ecf20Sopenharmony_ci		return PTR_ERR(vaddr);
8168c2ecf20Sopenharmony_ci
8178c2ecf20Sopenharmony_ci	/*
8188c2ecf20Sopenharmony_ci	 * This registers range is used to setup NAND settings. In case with
8198c2ecf20Sopenharmony_ci	 * TI AEMIF driver, the same memory address range is requested already
8208c2ecf20Sopenharmony_ci	 * by AEMIF, so we cannot request it twice, just ioremap.
8218c2ecf20Sopenharmony_ci	 * The AEMIF and NAND drivers not use the same registers in this range.
8228c2ecf20Sopenharmony_ci	 */
8238c2ecf20Sopenharmony_ci	base = devm_ioremap(&pdev->dev, res2->start, resource_size(res2));
8248c2ecf20Sopenharmony_ci	if (!base) {
8258c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "ioremap failed for resource %pR\n", res2);
8268c2ecf20Sopenharmony_ci		return -EADDRNOTAVAIL;
8278c2ecf20Sopenharmony_ci	}
8288c2ecf20Sopenharmony_ci
8298c2ecf20Sopenharmony_ci	info->pdev		= pdev;
8308c2ecf20Sopenharmony_ci	info->base		= base;
8318c2ecf20Sopenharmony_ci	info->vaddr		= vaddr;
8328c2ecf20Sopenharmony_ci
8338c2ecf20Sopenharmony_ci	mtd			= nand_to_mtd(&info->chip);
8348c2ecf20Sopenharmony_ci	mtd->dev.parent		= &pdev->dev;
8358c2ecf20Sopenharmony_ci	nand_set_flash_node(&info->chip, pdev->dev.of_node);
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_ci	/* options such as NAND_BBT_USE_FLASH */
8388c2ecf20Sopenharmony_ci	info->chip.bbt_options	= pdata->bbt_options;
8398c2ecf20Sopenharmony_ci	/* options such as 16-bit widths */
8408c2ecf20Sopenharmony_ci	info->chip.options	= pdata->options;
8418c2ecf20Sopenharmony_ci	info->chip.bbt_td	= pdata->bbt_td;
8428c2ecf20Sopenharmony_ci	info->chip.bbt_md	= pdata->bbt_md;
8438c2ecf20Sopenharmony_ci	info->timing		= pdata->timing;
8448c2ecf20Sopenharmony_ci
8458c2ecf20Sopenharmony_ci	info->current_cs	= info->vaddr;
8468c2ecf20Sopenharmony_ci	info->core_chipsel	= pdata->core_chipsel;
8478c2ecf20Sopenharmony_ci	info->mask_chipsel	= pdata->mask_chipsel;
8488c2ecf20Sopenharmony_ci
8498c2ecf20Sopenharmony_ci	/* use nandboot-capable ALE/CLE masks by default */
8508c2ecf20Sopenharmony_ci	info->mask_ale		= pdata->mask_ale ? : MASK_ALE;
8518c2ecf20Sopenharmony_ci	info->mask_cle		= pdata->mask_cle ? : MASK_CLE;
8528c2ecf20Sopenharmony_ci
8538c2ecf20Sopenharmony_ci	spin_lock_irq(&davinci_nand_lock);
8548c2ecf20Sopenharmony_ci
8558c2ecf20Sopenharmony_ci	/* put CSxNAND into NAND mode */
8568c2ecf20Sopenharmony_ci	val = davinci_nand_readl(info, NANDFCR_OFFSET);
8578c2ecf20Sopenharmony_ci	val |= BIT(info->core_chipsel);
8588c2ecf20Sopenharmony_ci	davinci_nand_writel(info, NANDFCR_OFFSET, val);
8598c2ecf20Sopenharmony_ci
8608c2ecf20Sopenharmony_ci	spin_unlock_irq(&davinci_nand_lock);
8618c2ecf20Sopenharmony_ci
8628c2ecf20Sopenharmony_ci	/* Scan to find existence of the device(s) */
8638c2ecf20Sopenharmony_ci	nand_controller_init(&info->controller);
8648c2ecf20Sopenharmony_ci	info->controller.ops = &davinci_nand_controller_ops;
8658c2ecf20Sopenharmony_ci	info->chip.controller = &info->controller;
8668c2ecf20Sopenharmony_ci	ret = nand_scan(&info->chip, pdata->mask_chipsel ? 2 : 1);
8678c2ecf20Sopenharmony_ci	if (ret < 0) {
8688c2ecf20Sopenharmony_ci		dev_dbg(&pdev->dev, "no NAND chip(s) found\n");
8698c2ecf20Sopenharmony_ci		return ret;
8708c2ecf20Sopenharmony_ci	}
8718c2ecf20Sopenharmony_ci
8728c2ecf20Sopenharmony_ci	if (pdata->parts)
8738c2ecf20Sopenharmony_ci		ret = mtd_device_register(mtd, pdata->parts, pdata->nr_parts);
8748c2ecf20Sopenharmony_ci	else
8758c2ecf20Sopenharmony_ci		ret = mtd_device_register(mtd, NULL, 0);
8768c2ecf20Sopenharmony_ci	if (ret < 0)
8778c2ecf20Sopenharmony_ci		goto err_cleanup_nand;
8788c2ecf20Sopenharmony_ci
8798c2ecf20Sopenharmony_ci	val = davinci_nand_readl(info, NRCSR_OFFSET);
8808c2ecf20Sopenharmony_ci	dev_info(&pdev->dev, "controller rev. %d.%d\n",
8818c2ecf20Sopenharmony_ci	       (val >> 8) & 0xff, val & 0xff);
8828c2ecf20Sopenharmony_ci
8838c2ecf20Sopenharmony_ci	return 0;
8848c2ecf20Sopenharmony_ci
8858c2ecf20Sopenharmony_cierr_cleanup_nand:
8868c2ecf20Sopenharmony_ci	nand_cleanup(&info->chip);
8878c2ecf20Sopenharmony_ci
8888c2ecf20Sopenharmony_ci	return ret;
8898c2ecf20Sopenharmony_ci}
8908c2ecf20Sopenharmony_ci
8918c2ecf20Sopenharmony_cistatic int nand_davinci_remove(struct platform_device *pdev)
8928c2ecf20Sopenharmony_ci{
8938c2ecf20Sopenharmony_ci	struct davinci_nand_info *info = platform_get_drvdata(pdev);
8948c2ecf20Sopenharmony_ci	struct nand_chip *chip = &info->chip;
8958c2ecf20Sopenharmony_ci	int ret;
8968c2ecf20Sopenharmony_ci
8978c2ecf20Sopenharmony_ci	spin_lock_irq(&davinci_nand_lock);
8988c2ecf20Sopenharmony_ci	if (info->chip.ecc.placement == NAND_ECC_PLACEMENT_INTERLEAVED)
8998c2ecf20Sopenharmony_ci		ecc4_busy = false;
9008c2ecf20Sopenharmony_ci	spin_unlock_irq(&davinci_nand_lock);
9018c2ecf20Sopenharmony_ci
9028c2ecf20Sopenharmony_ci	ret = mtd_device_unregister(nand_to_mtd(chip));
9038c2ecf20Sopenharmony_ci	WARN_ON(ret);
9048c2ecf20Sopenharmony_ci	nand_cleanup(chip);
9058c2ecf20Sopenharmony_ci
9068c2ecf20Sopenharmony_ci	return 0;
9078c2ecf20Sopenharmony_ci}
9088c2ecf20Sopenharmony_ci
9098c2ecf20Sopenharmony_cistatic struct platform_driver nand_davinci_driver = {
9108c2ecf20Sopenharmony_ci	.probe		= nand_davinci_probe,
9118c2ecf20Sopenharmony_ci	.remove		= nand_davinci_remove,
9128c2ecf20Sopenharmony_ci	.driver		= {
9138c2ecf20Sopenharmony_ci		.name	= "davinci_nand",
9148c2ecf20Sopenharmony_ci		.of_match_table = of_match_ptr(davinci_nand_of_match),
9158c2ecf20Sopenharmony_ci	},
9168c2ecf20Sopenharmony_ci};
9178c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:davinci_nand");
9188c2ecf20Sopenharmony_ci
9198c2ecf20Sopenharmony_cimodule_platform_driver(nand_davinci_driver);
9208c2ecf20Sopenharmony_ci
9218c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
9228c2ecf20Sopenharmony_ciMODULE_AUTHOR("Texas Instruments");
9238c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Davinci NAND flash driver");
9248c2ecf20Sopenharmony_ci
925