162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * davinci_nand.c - NAND Flash Driver for DaVinci family chips
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright © 2006 Texas Instruments.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Port to 2.6.23 Copyright © 2008 by:
862306a36Sopenharmony_ci *   Sander Huijsen <Shuijsen@optelecom-nkf.com>
962306a36Sopenharmony_ci *   Troy Kisky <troy.kisky@boundarydevices.com>
1062306a36Sopenharmony_ci *   Dirk Behme <Dirk.Behme@gmail.com>
1162306a36Sopenharmony_ci */
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include <linux/kernel.h>
1462306a36Sopenharmony_ci#include <linux/module.h>
1562306a36Sopenharmony_ci#include <linux/platform_device.h>
1662306a36Sopenharmony_ci#include <linux/err.h>
1762306a36Sopenharmony_ci#include <linux/iopoll.h>
1862306a36Sopenharmony_ci#include <linux/mtd/rawnand.h>
1962306a36Sopenharmony_ci#include <linux/mtd/partitions.h>
2062306a36Sopenharmony_ci#include <linux/slab.h>
2162306a36Sopenharmony_ci#include <linux/of.h>
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#include <linux/platform_data/mtd-davinci.h>
2462306a36Sopenharmony_ci#include <linux/platform_data/mtd-davinci-aemif.h>
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci/*
2762306a36Sopenharmony_ci * This is a device driver for the NAND flash controller found on the
2862306a36Sopenharmony_ci * various DaVinci family chips.  It handles up to four SoC chipselects,
2962306a36Sopenharmony_ci * and some flavors of secondary chipselect (e.g. based on A12) as used
3062306a36Sopenharmony_ci * with multichip packages.
3162306a36Sopenharmony_ci *
3262306a36Sopenharmony_ci * The 1-bit ECC hardware is supported, as well as the newer 4-bit ECC
3362306a36Sopenharmony_ci * available on chips like the DM355 and OMAP-L137 and needed with the
3462306a36Sopenharmony_ci * more error-prone MLC NAND chips.
3562306a36Sopenharmony_ci *
3662306a36Sopenharmony_ci * This driver assumes EM_WAIT connects all the NAND devices' RDY/nBUSY
3762306a36Sopenharmony_ci * outputs in a "wire-AND" configuration, with no per-chip signals.
3862306a36Sopenharmony_ci */
3962306a36Sopenharmony_cistruct davinci_nand_info {
4062306a36Sopenharmony_ci	struct nand_controller	controller;
4162306a36Sopenharmony_ci	struct nand_chip	chip;
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	struct platform_device	*pdev;
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	bool			is_readmode;
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	void __iomem		*base;
4862306a36Sopenharmony_ci	void __iomem		*vaddr;
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	void __iomem		*current_cs;
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	uint32_t		mask_chipsel;
5362306a36Sopenharmony_ci	uint32_t		mask_ale;
5462306a36Sopenharmony_ci	uint32_t		mask_cle;
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	uint32_t		core_chipsel;
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	struct davinci_aemif_timing	*timing;
5962306a36Sopenharmony_ci};
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_cistatic DEFINE_SPINLOCK(davinci_nand_lock);
6262306a36Sopenharmony_cistatic bool ecc4_busy;
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_cistatic inline struct davinci_nand_info *to_davinci_nand(struct mtd_info *mtd)
6562306a36Sopenharmony_ci{
6662306a36Sopenharmony_ci	return container_of(mtd_to_nand(mtd), struct davinci_nand_info, chip);
6762306a36Sopenharmony_ci}
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_cistatic inline unsigned int davinci_nand_readl(struct davinci_nand_info *info,
7062306a36Sopenharmony_ci		int offset)
7162306a36Sopenharmony_ci{
7262306a36Sopenharmony_ci	return __raw_readl(info->base + offset);
7362306a36Sopenharmony_ci}
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_cistatic inline void davinci_nand_writel(struct davinci_nand_info *info,
7662306a36Sopenharmony_ci		int offset, unsigned long value)
7762306a36Sopenharmony_ci{
7862306a36Sopenharmony_ci	__raw_writel(value, info->base + offset);
7962306a36Sopenharmony_ci}
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci/*----------------------------------------------------------------------*/
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci/*
8462306a36Sopenharmony_ci * 1-bit hardware ECC ... context maintained for each core chipselect
8562306a36Sopenharmony_ci */
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_cistatic inline uint32_t nand_davinci_readecc_1bit(struct mtd_info *mtd)
8862306a36Sopenharmony_ci{
8962306a36Sopenharmony_ci	struct davinci_nand_info *info = to_davinci_nand(mtd);
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	return davinci_nand_readl(info, NANDF1ECC_OFFSET
9262306a36Sopenharmony_ci			+ 4 * info->core_chipsel);
9362306a36Sopenharmony_ci}
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_cistatic void nand_davinci_hwctl_1bit(struct nand_chip *chip, int mode)
9662306a36Sopenharmony_ci{
9762306a36Sopenharmony_ci	struct davinci_nand_info *info;
9862306a36Sopenharmony_ci	uint32_t nandcfr;
9962306a36Sopenharmony_ci	unsigned long flags;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	info = to_davinci_nand(nand_to_mtd(chip));
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	/* Reset ECC hardware */
10462306a36Sopenharmony_ci	nand_davinci_readecc_1bit(nand_to_mtd(chip));
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	spin_lock_irqsave(&davinci_nand_lock, flags);
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	/* Restart ECC hardware */
10962306a36Sopenharmony_ci	nandcfr = davinci_nand_readl(info, NANDFCR_OFFSET);
11062306a36Sopenharmony_ci	nandcfr |= BIT(8 + info->core_chipsel);
11162306a36Sopenharmony_ci	davinci_nand_writel(info, NANDFCR_OFFSET, nandcfr);
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	spin_unlock_irqrestore(&davinci_nand_lock, flags);
11462306a36Sopenharmony_ci}
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci/*
11762306a36Sopenharmony_ci * Read hardware ECC value and pack into three bytes
11862306a36Sopenharmony_ci */
11962306a36Sopenharmony_cistatic int nand_davinci_calculate_1bit(struct nand_chip *chip,
12062306a36Sopenharmony_ci				       const u_char *dat, u_char *ecc_code)
12162306a36Sopenharmony_ci{
12262306a36Sopenharmony_ci	unsigned int ecc_val = nand_davinci_readecc_1bit(nand_to_mtd(chip));
12362306a36Sopenharmony_ci	unsigned int ecc24 = (ecc_val & 0x0fff) | ((ecc_val & 0x0fff0000) >> 4);
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	/* invert so that erased block ecc is correct */
12662306a36Sopenharmony_ci	ecc24 = ~ecc24;
12762306a36Sopenharmony_ci	ecc_code[0] = (u_char)(ecc24);
12862306a36Sopenharmony_ci	ecc_code[1] = (u_char)(ecc24 >> 8);
12962306a36Sopenharmony_ci	ecc_code[2] = (u_char)(ecc24 >> 16);
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	return 0;
13262306a36Sopenharmony_ci}
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_cistatic int nand_davinci_correct_1bit(struct nand_chip *chip, u_char *dat,
13562306a36Sopenharmony_ci				     u_char *read_ecc, u_char *calc_ecc)
13662306a36Sopenharmony_ci{
13762306a36Sopenharmony_ci	uint32_t eccNand = read_ecc[0] | (read_ecc[1] << 8) |
13862306a36Sopenharmony_ci					  (read_ecc[2] << 16);
13962306a36Sopenharmony_ci	uint32_t eccCalc = calc_ecc[0] | (calc_ecc[1] << 8) |
14062306a36Sopenharmony_ci					  (calc_ecc[2] << 16);
14162306a36Sopenharmony_ci	uint32_t diff = eccCalc ^ eccNand;
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	if (diff) {
14462306a36Sopenharmony_ci		if ((((diff >> 12) ^ diff) & 0xfff) == 0xfff) {
14562306a36Sopenharmony_ci			/* Correctable error */
14662306a36Sopenharmony_ci			if ((diff >> (12 + 3)) < chip->ecc.size) {
14762306a36Sopenharmony_ci				dat[diff >> (12 + 3)] ^= BIT((diff >> 12) & 7);
14862306a36Sopenharmony_ci				return 1;
14962306a36Sopenharmony_ci			} else {
15062306a36Sopenharmony_ci				return -EBADMSG;
15162306a36Sopenharmony_ci			}
15262306a36Sopenharmony_ci		} else if (!(diff & (diff - 1))) {
15362306a36Sopenharmony_ci			/* Single bit ECC error in the ECC itself,
15462306a36Sopenharmony_ci			 * nothing to fix */
15562306a36Sopenharmony_ci			return 1;
15662306a36Sopenharmony_ci		} else {
15762306a36Sopenharmony_ci			/* Uncorrectable error */
15862306a36Sopenharmony_ci			return -EBADMSG;
15962306a36Sopenharmony_ci		}
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	}
16262306a36Sopenharmony_ci	return 0;
16362306a36Sopenharmony_ci}
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci/*----------------------------------------------------------------------*/
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci/*
16862306a36Sopenharmony_ci * 4-bit hardware ECC ... context maintained over entire AEMIF
16962306a36Sopenharmony_ci *
17062306a36Sopenharmony_ci * This is a syndrome engine, but we avoid NAND_ECC_PLACEMENT_INTERLEAVED
17162306a36Sopenharmony_ci * since that forces use of a problematic "infix OOB" layout.
17262306a36Sopenharmony_ci * Among other things, it trashes manufacturer bad block markers.
17362306a36Sopenharmony_ci * Also, and specific to this hardware, it ECC-protects the "prepad"
17462306a36Sopenharmony_ci * in the OOB ... while having ECC protection for parts of OOB would
17562306a36Sopenharmony_ci * seem useful, the current MTD stack sometimes wants to update the
17662306a36Sopenharmony_ci * OOB without recomputing ECC.
17762306a36Sopenharmony_ci */
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_cistatic void nand_davinci_hwctl_4bit(struct nand_chip *chip, int mode)
18062306a36Sopenharmony_ci{
18162306a36Sopenharmony_ci	struct davinci_nand_info *info = to_davinci_nand(nand_to_mtd(chip));
18262306a36Sopenharmony_ci	unsigned long flags;
18362306a36Sopenharmony_ci	u32 val;
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	/* Reset ECC hardware */
18662306a36Sopenharmony_ci	davinci_nand_readl(info, NAND_4BIT_ECC1_OFFSET);
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	spin_lock_irqsave(&davinci_nand_lock, flags);
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	/* Start 4-bit ECC calculation for read/write */
19162306a36Sopenharmony_ci	val = davinci_nand_readl(info, NANDFCR_OFFSET);
19262306a36Sopenharmony_ci	val &= ~(0x03 << 4);
19362306a36Sopenharmony_ci	val |= (info->core_chipsel << 4) | BIT(12);
19462306a36Sopenharmony_ci	davinci_nand_writel(info, NANDFCR_OFFSET, val);
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	info->is_readmode = (mode == NAND_ECC_READ);
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	spin_unlock_irqrestore(&davinci_nand_lock, flags);
19962306a36Sopenharmony_ci}
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci/* Read raw ECC code after writing to NAND. */
20262306a36Sopenharmony_cistatic void
20362306a36Sopenharmony_cinand_davinci_readecc_4bit(struct davinci_nand_info *info, u32 code[4])
20462306a36Sopenharmony_ci{
20562306a36Sopenharmony_ci	const u32 mask = 0x03ff03ff;
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	code[0] = davinci_nand_readl(info, NAND_4BIT_ECC1_OFFSET) & mask;
20862306a36Sopenharmony_ci	code[1] = davinci_nand_readl(info, NAND_4BIT_ECC2_OFFSET) & mask;
20962306a36Sopenharmony_ci	code[2] = davinci_nand_readl(info, NAND_4BIT_ECC3_OFFSET) & mask;
21062306a36Sopenharmony_ci	code[3] = davinci_nand_readl(info, NAND_4BIT_ECC4_OFFSET) & mask;
21162306a36Sopenharmony_ci}
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci/* Terminate read ECC; or return ECC (as bytes) of data written to NAND. */
21462306a36Sopenharmony_cistatic int nand_davinci_calculate_4bit(struct nand_chip *chip,
21562306a36Sopenharmony_ci				       const u_char *dat, u_char *ecc_code)
21662306a36Sopenharmony_ci{
21762306a36Sopenharmony_ci	struct davinci_nand_info *info = to_davinci_nand(nand_to_mtd(chip));
21862306a36Sopenharmony_ci	u32 raw_ecc[4], *p;
21962306a36Sopenharmony_ci	unsigned i;
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	/* After a read, terminate ECC calculation by a dummy read
22262306a36Sopenharmony_ci	 * of some 4-bit ECC register.  ECC covers everything that
22362306a36Sopenharmony_ci	 * was read; correct() just uses the hardware state, so
22462306a36Sopenharmony_ci	 * ecc_code is not needed.
22562306a36Sopenharmony_ci	 */
22662306a36Sopenharmony_ci	if (info->is_readmode) {
22762306a36Sopenharmony_ci		davinci_nand_readl(info, NAND_4BIT_ECC1_OFFSET);
22862306a36Sopenharmony_ci		return 0;
22962306a36Sopenharmony_ci	}
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	/* Pack eight raw 10-bit ecc values into ten bytes, making
23262306a36Sopenharmony_ci	 * two passes which each convert four values (in upper and
23362306a36Sopenharmony_ci	 * lower halves of two 32-bit words) into five bytes.  The
23462306a36Sopenharmony_ci	 * ROM boot loader uses this same packing scheme.
23562306a36Sopenharmony_ci	 */
23662306a36Sopenharmony_ci	nand_davinci_readecc_4bit(info, raw_ecc);
23762306a36Sopenharmony_ci	for (i = 0, p = raw_ecc; i < 2; i++, p += 2) {
23862306a36Sopenharmony_ci		*ecc_code++ =   p[0]        & 0xff;
23962306a36Sopenharmony_ci		*ecc_code++ = ((p[0] >>  8) & 0x03) | ((p[0] >> 14) & 0xfc);
24062306a36Sopenharmony_ci		*ecc_code++ = ((p[0] >> 22) & 0x0f) | ((p[1] <<  4) & 0xf0);
24162306a36Sopenharmony_ci		*ecc_code++ = ((p[1] >>  4) & 0x3f) | ((p[1] >> 10) & 0xc0);
24262306a36Sopenharmony_ci		*ecc_code++ =  (p[1] >> 18) & 0xff;
24362306a36Sopenharmony_ci	}
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	return 0;
24662306a36Sopenharmony_ci}
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci/* Correct up to 4 bits in data we just read, using state left in the
24962306a36Sopenharmony_ci * hardware plus the ecc_code computed when it was first written.
25062306a36Sopenharmony_ci */
25162306a36Sopenharmony_cistatic int nand_davinci_correct_4bit(struct nand_chip *chip, u_char *data,
25262306a36Sopenharmony_ci				     u_char *ecc_code, u_char *null)
25362306a36Sopenharmony_ci{
25462306a36Sopenharmony_ci	int i;
25562306a36Sopenharmony_ci	struct davinci_nand_info *info = to_davinci_nand(nand_to_mtd(chip));
25662306a36Sopenharmony_ci	unsigned short ecc10[8];
25762306a36Sopenharmony_ci	unsigned short *ecc16;
25862306a36Sopenharmony_ci	u32 syndrome[4];
25962306a36Sopenharmony_ci	u32 ecc_state;
26062306a36Sopenharmony_ci	unsigned num_errors, corrected;
26162306a36Sopenharmony_ci	unsigned long timeo;
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	/* Unpack ten bytes into eight 10 bit values.  We know we're
26462306a36Sopenharmony_ci	 * little-endian, and use type punning for less shifting/masking.
26562306a36Sopenharmony_ci	 */
26662306a36Sopenharmony_ci	if (WARN_ON(0x01 & (uintptr_t)ecc_code))
26762306a36Sopenharmony_ci		return -EINVAL;
26862306a36Sopenharmony_ci	ecc16 = (unsigned short *)ecc_code;
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	ecc10[0] =  (ecc16[0] >>  0) & 0x3ff;
27162306a36Sopenharmony_ci	ecc10[1] = ((ecc16[0] >> 10) & 0x3f) | ((ecc16[1] << 6) & 0x3c0);
27262306a36Sopenharmony_ci	ecc10[2] =  (ecc16[1] >>  4) & 0x3ff;
27362306a36Sopenharmony_ci	ecc10[3] = ((ecc16[1] >> 14) & 0x3)  | ((ecc16[2] << 2) & 0x3fc);
27462306a36Sopenharmony_ci	ecc10[4] =  (ecc16[2] >>  8)         | ((ecc16[3] << 8) & 0x300);
27562306a36Sopenharmony_ci	ecc10[5] =  (ecc16[3] >>  2) & 0x3ff;
27662306a36Sopenharmony_ci	ecc10[6] = ((ecc16[3] >> 12) & 0xf)  | ((ecc16[4] << 4) & 0x3f0);
27762306a36Sopenharmony_ci	ecc10[7] =  (ecc16[4] >>  6) & 0x3ff;
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	/* Tell ECC controller about the expected ECC codes. */
28062306a36Sopenharmony_ci	for (i = 7; i >= 0; i--)
28162306a36Sopenharmony_ci		davinci_nand_writel(info, NAND_4BIT_ECC_LOAD_OFFSET, ecc10[i]);
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	/* Allow time for syndrome calculation ... then read it.
28462306a36Sopenharmony_ci	 * A syndrome of all zeroes 0 means no detected errors.
28562306a36Sopenharmony_ci	 */
28662306a36Sopenharmony_ci	davinci_nand_readl(info, NANDFSR_OFFSET);
28762306a36Sopenharmony_ci	nand_davinci_readecc_4bit(info, syndrome);
28862306a36Sopenharmony_ci	if (!(syndrome[0] | syndrome[1] | syndrome[2] | syndrome[3]))
28962306a36Sopenharmony_ci		return 0;
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	/*
29262306a36Sopenharmony_ci	 * Clear any previous address calculation by doing a dummy read of an
29362306a36Sopenharmony_ci	 * error address register.
29462306a36Sopenharmony_ci	 */
29562306a36Sopenharmony_ci	davinci_nand_readl(info, NAND_ERR_ADD1_OFFSET);
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	/* Start address calculation, and wait for it to complete.
29862306a36Sopenharmony_ci	 * We _could_ start reading more data while this is working,
29962306a36Sopenharmony_ci	 * to speed up the overall page read.
30062306a36Sopenharmony_ci	 */
30162306a36Sopenharmony_ci	davinci_nand_writel(info, NANDFCR_OFFSET,
30262306a36Sopenharmony_ci			davinci_nand_readl(info, NANDFCR_OFFSET) | BIT(13));
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	/*
30562306a36Sopenharmony_ci	 * ECC_STATE field reads 0x3 (Error correction complete) immediately
30662306a36Sopenharmony_ci	 * after setting the 4BITECC_ADD_CALC_START bit. So if you immediately
30762306a36Sopenharmony_ci	 * begin trying to poll for the state, you may fall right out of your
30862306a36Sopenharmony_ci	 * loop without any of the correction calculations having taken place.
30962306a36Sopenharmony_ci	 * The recommendation from the hardware team is to initially delay as
31062306a36Sopenharmony_ci	 * long as ECC_STATE reads less than 4. After that, ECC HW has entered
31162306a36Sopenharmony_ci	 * correction state.
31262306a36Sopenharmony_ci	 */
31362306a36Sopenharmony_ci	timeo = jiffies + usecs_to_jiffies(100);
31462306a36Sopenharmony_ci	do {
31562306a36Sopenharmony_ci		ecc_state = (davinci_nand_readl(info,
31662306a36Sopenharmony_ci				NANDFSR_OFFSET) >> 8) & 0x0f;
31762306a36Sopenharmony_ci		cpu_relax();
31862306a36Sopenharmony_ci	} while ((ecc_state < 4) && time_before(jiffies, timeo));
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	for (;;) {
32162306a36Sopenharmony_ci		u32	fsr = davinci_nand_readl(info, NANDFSR_OFFSET);
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci		switch ((fsr >> 8) & 0x0f) {
32462306a36Sopenharmony_ci		case 0:		/* no error, should not happen */
32562306a36Sopenharmony_ci			davinci_nand_readl(info, NAND_ERR_ERRVAL1_OFFSET);
32662306a36Sopenharmony_ci			return 0;
32762306a36Sopenharmony_ci		case 1:		/* five or more errors detected */
32862306a36Sopenharmony_ci			davinci_nand_readl(info, NAND_ERR_ERRVAL1_OFFSET);
32962306a36Sopenharmony_ci			return -EBADMSG;
33062306a36Sopenharmony_ci		case 2:		/* error addresses computed */
33162306a36Sopenharmony_ci		case 3:
33262306a36Sopenharmony_ci			num_errors = 1 + ((fsr >> 16) & 0x03);
33362306a36Sopenharmony_ci			goto correct;
33462306a36Sopenharmony_ci		default:	/* still working on it */
33562306a36Sopenharmony_ci			cpu_relax();
33662306a36Sopenharmony_ci			continue;
33762306a36Sopenharmony_ci		}
33862306a36Sopenharmony_ci	}
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_cicorrect:
34162306a36Sopenharmony_ci	/* correct each error */
34262306a36Sopenharmony_ci	for (i = 0, corrected = 0; i < num_errors; i++) {
34362306a36Sopenharmony_ci		int error_address, error_value;
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci		if (i > 1) {
34662306a36Sopenharmony_ci			error_address = davinci_nand_readl(info,
34762306a36Sopenharmony_ci						NAND_ERR_ADD2_OFFSET);
34862306a36Sopenharmony_ci			error_value = davinci_nand_readl(info,
34962306a36Sopenharmony_ci						NAND_ERR_ERRVAL2_OFFSET);
35062306a36Sopenharmony_ci		} else {
35162306a36Sopenharmony_ci			error_address = davinci_nand_readl(info,
35262306a36Sopenharmony_ci						NAND_ERR_ADD1_OFFSET);
35362306a36Sopenharmony_ci			error_value = davinci_nand_readl(info,
35462306a36Sopenharmony_ci						NAND_ERR_ERRVAL1_OFFSET);
35562306a36Sopenharmony_ci		}
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci		if (i & 1) {
35862306a36Sopenharmony_ci			error_address >>= 16;
35962306a36Sopenharmony_ci			error_value >>= 16;
36062306a36Sopenharmony_ci		}
36162306a36Sopenharmony_ci		error_address &= 0x3ff;
36262306a36Sopenharmony_ci		error_address = (512 + 7) - error_address;
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci		if (error_address < 512) {
36562306a36Sopenharmony_ci			data[error_address] ^= error_value;
36662306a36Sopenharmony_ci			corrected++;
36762306a36Sopenharmony_ci		}
36862306a36Sopenharmony_ci	}
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	return corrected;
37162306a36Sopenharmony_ci}
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci/*----------------------------------------------------------------------*/
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci/* An ECC layout for using 4-bit ECC with small-page flash, storing
37662306a36Sopenharmony_ci * ten ECC bytes plus the manufacturer's bad block marker byte, and
37762306a36Sopenharmony_ci * and not overlapping the default BBT markers.
37862306a36Sopenharmony_ci */
37962306a36Sopenharmony_cistatic int hwecc4_ooblayout_small_ecc(struct mtd_info *mtd, int section,
38062306a36Sopenharmony_ci				      struct mtd_oob_region *oobregion)
38162306a36Sopenharmony_ci{
38262306a36Sopenharmony_ci	if (section > 2)
38362306a36Sopenharmony_ci		return -ERANGE;
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	if (!section) {
38662306a36Sopenharmony_ci		oobregion->offset = 0;
38762306a36Sopenharmony_ci		oobregion->length = 5;
38862306a36Sopenharmony_ci	} else if (section == 1) {
38962306a36Sopenharmony_ci		oobregion->offset = 6;
39062306a36Sopenharmony_ci		oobregion->length = 2;
39162306a36Sopenharmony_ci	} else {
39262306a36Sopenharmony_ci		oobregion->offset = 13;
39362306a36Sopenharmony_ci		oobregion->length = 3;
39462306a36Sopenharmony_ci	}
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	return 0;
39762306a36Sopenharmony_ci}
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_cistatic int hwecc4_ooblayout_small_free(struct mtd_info *mtd, int section,
40062306a36Sopenharmony_ci				       struct mtd_oob_region *oobregion)
40162306a36Sopenharmony_ci{
40262306a36Sopenharmony_ci	if (section > 1)
40362306a36Sopenharmony_ci		return -ERANGE;
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	if (!section) {
40662306a36Sopenharmony_ci		oobregion->offset = 8;
40762306a36Sopenharmony_ci		oobregion->length = 5;
40862306a36Sopenharmony_ci	} else {
40962306a36Sopenharmony_ci		oobregion->offset = 16;
41062306a36Sopenharmony_ci		oobregion->length = mtd->oobsize - 16;
41162306a36Sopenharmony_ci	}
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	return 0;
41462306a36Sopenharmony_ci}
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_cistatic const struct mtd_ooblayout_ops hwecc4_small_ooblayout_ops = {
41762306a36Sopenharmony_ci	.ecc = hwecc4_ooblayout_small_ecc,
41862306a36Sopenharmony_ci	.free = hwecc4_ooblayout_small_free,
41962306a36Sopenharmony_ci};
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci#if defined(CONFIG_OF)
42262306a36Sopenharmony_cistatic const struct of_device_id davinci_nand_of_match[] = {
42362306a36Sopenharmony_ci	{.compatible = "ti,davinci-nand", },
42462306a36Sopenharmony_ci	{.compatible = "ti,keystone-nand", },
42562306a36Sopenharmony_ci	{},
42662306a36Sopenharmony_ci};
42762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, davinci_nand_of_match);
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_cistatic struct davinci_nand_pdata
43062306a36Sopenharmony_ci	*nand_davinci_get_pdata(struct platform_device *pdev)
43162306a36Sopenharmony_ci{
43262306a36Sopenharmony_ci	if (!dev_get_platdata(&pdev->dev) && pdev->dev.of_node) {
43362306a36Sopenharmony_ci		struct davinci_nand_pdata *pdata;
43462306a36Sopenharmony_ci		const char *mode;
43562306a36Sopenharmony_ci		u32 prop;
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci		pdata =  devm_kzalloc(&pdev->dev,
43862306a36Sopenharmony_ci				sizeof(struct davinci_nand_pdata),
43962306a36Sopenharmony_ci				GFP_KERNEL);
44062306a36Sopenharmony_ci		pdev->dev.platform_data = pdata;
44162306a36Sopenharmony_ci		if (!pdata)
44262306a36Sopenharmony_ci			return ERR_PTR(-ENOMEM);
44362306a36Sopenharmony_ci		if (!of_property_read_u32(pdev->dev.of_node,
44462306a36Sopenharmony_ci			"ti,davinci-chipselect", &prop))
44562306a36Sopenharmony_ci			pdata->core_chipsel = prop;
44662306a36Sopenharmony_ci		else
44762306a36Sopenharmony_ci			return ERR_PTR(-EINVAL);
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci		if (!of_property_read_u32(pdev->dev.of_node,
45062306a36Sopenharmony_ci			"ti,davinci-mask-ale", &prop))
45162306a36Sopenharmony_ci			pdata->mask_ale = prop;
45262306a36Sopenharmony_ci		if (!of_property_read_u32(pdev->dev.of_node,
45362306a36Sopenharmony_ci			"ti,davinci-mask-cle", &prop))
45462306a36Sopenharmony_ci			pdata->mask_cle = prop;
45562306a36Sopenharmony_ci		if (!of_property_read_u32(pdev->dev.of_node,
45662306a36Sopenharmony_ci			"ti,davinci-mask-chipsel", &prop))
45762306a36Sopenharmony_ci			pdata->mask_chipsel = prop;
45862306a36Sopenharmony_ci		if (!of_property_read_string(pdev->dev.of_node,
45962306a36Sopenharmony_ci			"ti,davinci-ecc-mode", &mode)) {
46062306a36Sopenharmony_ci			if (!strncmp("none", mode, 4))
46162306a36Sopenharmony_ci				pdata->engine_type = NAND_ECC_ENGINE_TYPE_NONE;
46262306a36Sopenharmony_ci			if (!strncmp("soft", mode, 4))
46362306a36Sopenharmony_ci				pdata->engine_type = NAND_ECC_ENGINE_TYPE_SOFT;
46462306a36Sopenharmony_ci			if (!strncmp("hw", mode, 2))
46562306a36Sopenharmony_ci				pdata->engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST;
46662306a36Sopenharmony_ci		}
46762306a36Sopenharmony_ci		if (!of_property_read_u32(pdev->dev.of_node,
46862306a36Sopenharmony_ci			"ti,davinci-ecc-bits", &prop))
46962306a36Sopenharmony_ci			pdata->ecc_bits = prop;
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci		if (!of_property_read_u32(pdev->dev.of_node,
47262306a36Sopenharmony_ci			"ti,davinci-nand-buswidth", &prop) && prop == 16)
47362306a36Sopenharmony_ci			pdata->options |= NAND_BUSWIDTH_16;
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci		if (of_property_read_bool(pdev->dev.of_node,
47662306a36Sopenharmony_ci			"ti,davinci-nand-use-bbt"))
47762306a36Sopenharmony_ci			pdata->bbt_options = NAND_BBT_USE_FLASH;
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci		/*
48062306a36Sopenharmony_ci		 * Since kernel v4.8, this driver has been fixed to enable
48162306a36Sopenharmony_ci		 * use of 4-bit hardware ECC with subpages and verified on
48262306a36Sopenharmony_ci		 * TI's keystone EVMs (K2L, K2HK and K2E).
48362306a36Sopenharmony_ci		 * However, in the interest of not breaking systems using
48462306a36Sopenharmony_ci		 * existing UBI partitions, sub-page writes are not being
48562306a36Sopenharmony_ci		 * (re)enabled. If you want to use subpage writes on Keystone
48662306a36Sopenharmony_ci		 * platforms (i.e. do not have any existing UBI partitions),
48762306a36Sopenharmony_ci		 * then use "ti,davinci-nand" as the compatible in your
48862306a36Sopenharmony_ci		 * device-tree file.
48962306a36Sopenharmony_ci		 */
49062306a36Sopenharmony_ci		if (of_device_is_compatible(pdev->dev.of_node,
49162306a36Sopenharmony_ci					    "ti,keystone-nand")) {
49262306a36Sopenharmony_ci			pdata->options |= NAND_NO_SUBPAGE_WRITE;
49362306a36Sopenharmony_ci		}
49462306a36Sopenharmony_ci	}
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	return dev_get_platdata(&pdev->dev);
49762306a36Sopenharmony_ci}
49862306a36Sopenharmony_ci#else
49962306a36Sopenharmony_cistatic struct davinci_nand_pdata
50062306a36Sopenharmony_ci	*nand_davinci_get_pdata(struct platform_device *pdev)
50162306a36Sopenharmony_ci{
50262306a36Sopenharmony_ci	return dev_get_platdata(&pdev->dev);
50362306a36Sopenharmony_ci}
50462306a36Sopenharmony_ci#endif
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_cistatic int davinci_nand_attach_chip(struct nand_chip *chip)
50762306a36Sopenharmony_ci{
50862306a36Sopenharmony_ci	struct mtd_info *mtd = nand_to_mtd(chip);
50962306a36Sopenharmony_ci	struct davinci_nand_info *info = to_davinci_nand(mtd);
51062306a36Sopenharmony_ci	struct davinci_nand_pdata *pdata = nand_davinci_get_pdata(info->pdev);
51162306a36Sopenharmony_ci	int ret = 0;
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	if (IS_ERR(pdata))
51462306a36Sopenharmony_ci		return PTR_ERR(pdata);
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	/* Use board-specific ECC config */
51762306a36Sopenharmony_ci	chip->ecc.engine_type = pdata->engine_type;
51862306a36Sopenharmony_ci	chip->ecc.placement = pdata->ecc_placement;
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	switch (chip->ecc.engine_type) {
52162306a36Sopenharmony_ci	case NAND_ECC_ENGINE_TYPE_NONE:
52262306a36Sopenharmony_ci		pdata->ecc_bits = 0;
52362306a36Sopenharmony_ci		break;
52462306a36Sopenharmony_ci	case NAND_ECC_ENGINE_TYPE_SOFT:
52562306a36Sopenharmony_ci		pdata->ecc_bits = 0;
52662306a36Sopenharmony_ci		/*
52762306a36Sopenharmony_ci		 * This driver expects Hamming based ECC when engine_type is set
52862306a36Sopenharmony_ci		 * to NAND_ECC_ENGINE_TYPE_SOFT. Force ecc.algo to
52962306a36Sopenharmony_ci		 * NAND_ECC_ALGO_HAMMING to avoid adding an extra ->ecc_algo
53062306a36Sopenharmony_ci		 * field to davinci_nand_pdata.
53162306a36Sopenharmony_ci		 */
53262306a36Sopenharmony_ci		chip->ecc.algo = NAND_ECC_ALGO_HAMMING;
53362306a36Sopenharmony_ci		break;
53462306a36Sopenharmony_ci	case NAND_ECC_ENGINE_TYPE_ON_HOST:
53562306a36Sopenharmony_ci		if (pdata->ecc_bits == 4) {
53662306a36Sopenharmony_ci			int chunks = mtd->writesize / 512;
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci			if (!chunks || mtd->oobsize < 16) {
53962306a36Sopenharmony_ci				dev_dbg(&info->pdev->dev, "too small\n");
54062306a36Sopenharmony_ci				return -EINVAL;
54162306a36Sopenharmony_ci			}
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci			/*
54462306a36Sopenharmony_ci			 * No sanity checks:  CPUs must support this,
54562306a36Sopenharmony_ci			 * and the chips may not use NAND_BUSWIDTH_16.
54662306a36Sopenharmony_ci			 */
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci			/* No sharing 4-bit hardware between chipselects yet */
54962306a36Sopenharmony_ci			spin_lock_irq(&davinci_nand_lock);
55062306a36Sopenharmony_ci			if (ecc4_busy)
55162306a36Sopenharmony_ci				ret = -EBUSY;
55262306a36Sopenharmony_ci			else
55362306a36Sopenharmony_ci				ecc4_busy = true;
55462306a36Sopenharmony_ci			spin_unlock_irq(&davinci_nand_lock);
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci			if (ret == -EBUSY)
55762306a36Sopenharmony_ci				return ret;
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci			chip->ecc.calculate = nand_davinci_calculate_4bit;
56062306a36Sopenharmony_ci			chip->ecc.correct = nand_davinci_correct_4bit;
56162306a36Sopenharmony_ci			chip->ecc.hwctl = nand_davinci_hwctl_4bit;
56262306a36Sopenharmony_ci			chip->ecc.bytes = 10;
56362306a36Sopenharmony_ci			chip->ecc.options = NAND_ECC_GENERIC_ERASED_CHECK;
56462306a36Sopenharmony_ci			chip->ecc.algo = NAND_ECC_ALGO_BCH;
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci			/*
56762306a36Sopenharmony_ci			 * Update ECC layout if needed ... for 1-bit HW ECC, the
56862306a36Sopenharmony_ci			 * default is OK, but it allocates 6 bytes when only 3
56962306a36Sopenharmony_ci			 * are needed (for each 512 bytes). For 4-bit HW ECC,
57062306a36Sopenharmony_ci			 * the default is not usable: 10 bytes needed, not 6.
57162306a36Sopenharmony_ci			 *
57262306a36Sopenharmony_ci			 * For small page chips, preserve the manufacturer's
57362306a36Sopenharmony_ci			 * badblock marking data ... and make sure a flash BBT
57462306a36Sopenharmony_ci			 * table marker fits in the free bytes.
57562306a36Sopenharmony_ci			 */
57662306a36Sopenharmony_ci			if (chunks == 1) {
57762306a36Sopenharmony_ci				mtd_set_ooblayout(mtd,
57862306a36Sopenharmony_ci						  &hwecc4_small_ooblayout_ops);
57962306a36Sopenharmony_ci			} else if (chunks == 4 || chunks == 8) {
58062306a36Sopenharmony_ci				mtd_set_ooblayout(mtd,
58162306a36Sopenharmony_ci						  nand_get_large_page_ooblayout());
58262306a36Sopenharmony_ci				chip->ecc.read_page = nand_read_page_hwecc_oob_first;
58362306a36Sopenharmony_ci			} else {
58462306a36Sopenharmony_ci				return -EIO;
58562306a36Sopenharmony_ci			}
58662306a36Sopenharmony_ci		} else {
58762306a36Sopenharmony_ci			/* 1bit ecc hamming */
58862306a36Sopenharmony_ci			chip->ecc.calculate = nand_davinci_calculate_1bit;
58962306a36Sopenharmony_ci			chip->ecc.correct = nand_davinci_correct_1bit;
59062306a36Sopenharmony_ci			chip->ecc.hwctl = nand_davinci_hwctl_1bit;
59162306a36Sopenharmony_ci			chip->ecc.bytes = 3;
59262306a36Sopenharmony_ci			chip->ecc.algo = NAND_ECC_ALGO_HAMMING;
59362306a36Sopenharmony_ci		}
59462306a36Sopenharmony_ci		chip->ecc.size = 512;
59562306a36Sopenharmony_ci		chip->ecc.strength = pdata->ecc_bits;
59662306a36Sopenharmony_ci		break;
59762306a36Sopenharmony_ci	default:
59862306a36Sopenharmony_ci		return -EINVAL;
59962306a36Sopenharmony_ci	}
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci	return ret;
60262306a36Sopenharmony_ci}
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_cistatic void nand_davinci_data_in(struct davinci_nand_info *info, void *buf,
60562306a36Sopenharmony_ci				 unsigned int len, bool force_8bit)
60662306a36Sopenharmony_ci{
60762306a36Sopenharmony_ci	u32 alignment = ((uintptr_t)buf | len) & 3;
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	if (force_8bit || (alignment & 1))
61062306a36Sopenharmony_ci		ioread8_rep(info->current_cs, buf, len);
61162306a36Sopenharmony_ci	else if (alignment & 3)
61262306a36Sopenharmony_ci		ioread16_rep(info->current_cs, buf, len >> 1);
61362306a36Sopenharmony_ci	else
61462306a36Sopenharmony_ci		ioread32_rep(info->current_cs, buf, len >> 2);
61562306a36Sopenharmony_ci}
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_cistatic void nand_davinci_data_out(struct davinci_nand_info *info,
61862306a36Sopenharmony_ci				  const void *buf, unsigned int len,
61962306a36Sopenharmony_ci				  bool force_8bit)
62062306a36Sopenharmony_ci{
62162306a36Sopenharmony_ci	u32 alignment = ((uintptr_t)buf | len) & 3;
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci	if (force_8bit || (alignment & 1))
62462306a36Sopenharmony_ci		iowrite8_rep(info->current_cs, buf, len);
62562306a36Sopenharmony_ci	else if (alignment & 3)
62662306a36Sopenharmony_ci		iowrite16_rep(info->current_cs, buf, len >> 1);
62762306a36Sopenharmony_ci	else
62862306a36Sopenharmony_ci		iowrite32_rep(info->current_cs, buf, len >> 2);
62962306a36Sopenharmony_ci}
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_cistatic int davinci_nand_exec_instr(struct davinci_nand_info *info,
63262306a36Sopenharmony_ci				   const struct nand_op_instr *instr)
63362306a36Sopenharmony_ci{
63462306a36Sopenharmony_ci	unsigned int i, timeout_us;
63562306a36Sopenharmony_ci	u32 status;
63662306a36Sopenharmony_ci	int ret;
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci	switch (instr->type) {
63962306a36Sopenharmony_ci	case NAND_OP_CMD_INSTR:
64062306a36Sopenharmony_ci		iowrite8(instr->ctx.cmd.opcode,
64162306a36Sopenharmony_ci			 info->current_cs + info->mask_cle);
64262306a36Sopenharmony_ci		break;
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_ci	case NAND_OP_ADDR_INSTR:
64562306a36Sopenharmony_ci		for (i = 0; i < instr->ctx.addr.naddrs; i++) {
64662306a36Sopenharmony_ci			iowrite8(instr->ctx.addr.addrs[i],
64762306a36Sopenharmony_ci				 info->current_cs + info->mask_ale);
64862306a36Sopenharmony_ci		}
64962306a36Sopenharmony_ci		break;
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci	case NAND_OP_DATA_IN_INSTR:
65262306a36Sopenharmony_ci		nand_davinci_data_in(info, instr->ctx.data.buf.in,
65362306a36Sopenharmony_ci				     instr->ctx.data.len,
65462306a36Sopenharmony_ci				     instr->ctx.data.force_8bit);
65562306a36Sopenharmony_ci		break;
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci	case NAND_OP_DATA_OUT_INSTR:
65862306a36Sopenharmony_ci		nand_davinci_data_out(info, instr->ctx.data.buf.out,
65962306a36Sopenharmony_ci				      instr->ctx.data.len,
66062306a36Sopenharmony_ci				      instr->ctx.data.force_8bit);
66162306a36Sopenharmony_ci		break;
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci	case NAND_OP_WAITRDY_INSTR:
66462306a36Sopenharmony_ci		timeout_us = instr->ctx.waitrdy.timeout_ms * 1000;
66562306a36Sopenharmony_ci		ret = readl_relaxed_poll_timeout(info->base + NANDFSR_OFFSET,
66662306a36Sopenharmony_ci						 status, status & BIT(0), 100,
66762306a36Sopenharmony_ci						 timeout_us);
66862306a36Sopenharmony_ci		if (ret)
66962306a36Sopenharmony_ci			return ret;
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ci		break;
67262306a36Sopenharmony_ci	}
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci	if (instr->delay_ns)
67562306a36Sopenharmony_ci		ndelay(instr->delay_ns);
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ci	return 0;
67862306a36Sopenharmony_ci}
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_cistatic int davinci_nand_exec_op(struct nand_chip *chip,
68162306a36Sopenharmony_ci				const struct nand_operation *op,
68262306a36Sopenharmony_ci				bool check_only)
68362306a36Sopenharmony_ci{
68462306a36Sopenharmony_ci	struct davinci_nand_info *info = to_davinci_nand(nand_to_mtd(chip));
68562306a36Sopenharmony_ci	unsigned int i;
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci	if (check_only)
68862306a36Sopenharmony_ci		return 0;
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci	info->current_cs = info->vaddr + (op->cs * info->mask_chipsel);
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci	for (i = 0; i < op->ninstrs; i++) {
69362306a36Sopenharmony_ci		int ret;
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci		ret = davinci_nand_exec_instr(info, &op->instrs[i]);
69662306a36Sopenharmony_ci		if (ret)
69762306a36Sopenharmony_ci			return ret;
69862306a36Sopenharmony_ci	}
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci	return 0;
70162306a36Sopenharmony_ci}
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_cistatic const struct nand_controller_ops davinci_nand_controller_ops = {
70462306a36Sopenharmony_ci	.attach_chip = davinci_nand_attach_chip,
70562306a36Sopenharmony_ci	.exec_op = davinci_nand_exec_op,
70662306a36Sopenharmony_ci};
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_cistatic int nand_davinci_probe(struct platform_device *pdev)
70962306a36Sopenharmony_ci{
71062306a36Sopenharmony_ci	struct davinci_nand_pdata	*pdata;
71162306a36Sopenharmony_ci	struct davinci_nand_info	*info;
71262306a36Sopenharmony_ci	struct resource			*res1;
71362306a36Sopenharmony_ci	struct resource			*res2;
71462306a36Sopenharmony_ci	void __iomem			*vaddr;
71562306a36Sopenharmony_ci	void __iomem			*base;
71662306a36Sopenharmony_ci	int				ret;
71762306a36Sopenharmony_ci	uint32_t			val;
71862306a36Sopenharmony_ci	struct mtd_info			*mtd;
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci	pdata = nand_davinci_get_pdata(pdev);
72162306a36Sopenharmony_ci	if (IS_ERR(pdata))
72262306a36Sopenharmony_ci		return PTR_ERR(pdata);
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci	/* insist on board-specific configuration */
72562306a36Sopenharmony_ci	if (!pdata)
72662306a36Sopenharmony_ci		return -ENODEV;
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci	/* which external chipselect will we be managing? */
72962306a36Sopenharmony_ci	if (pdata->core_chipsel > 3)
73062306a36Sopenharmony_ci		return -ENODEV;
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
73362306a36Sopenharmony_ci	if (!info)
73462306a36Sopenharmony_ci		return -ENOMEM;
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci	platform_set_drvdata(pdev, info);
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ci	res1 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
73962306a36Sopenharmony_ci	res2 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
74062306a36Sopenharmony_ci	if (!res1 || !res2) {
74162306a36Sopenharmony_ci		dev_err(&pdev->dev, "resource missing\n");
74262306a36Sopenharmony_ci		return -EINVAL;
74362306a36Sopenharmony_ci	}
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ci	vaddr = devm_ioremap_resource(&pdev->dev, res1);
74662306a36Sopenharmony_ci	if (IS_ERR(vaddr))
74762306a36Sopenharmony_ci		return PTR_ERR(vaddr);
74862306a36Sopenharmony_ci
74962306a36Sopenharmony_ci	/*
75062306a36Sopenharmony_ci	 * This registers range is used to setup NAND settings. In case with
75162306a36Sopenharmony_ci	 * TI AEMIF driver, the same memory address range is requested already
75262306a36Sopenharmony_ci	 * by AEMIF, so we cannot request it twice, just ioremap.
75362306a36Sopenharmony_ci	 * The AEMIF and NAND drivers not use the same registers in this range.
75462306a36Sopenharmony_ci	 */
75562306a36Sopenharmony_ci	base = devm_ioremap(&pdev->dev, res2->start, resource_size(res2));
75662306a36Sopenharmony_ci	if (!base) {
75762306a36Sopenharmony_ci		dev_err(&pdev->dev, "ioremap failed for resource %pR\n", res2);
75862306a36Sopenharmony_ci		return -EADDRNOTAVAIL;
75962306a36Sopenharmony_ci	}
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ci	info->pdev		= pdev;
76262306a36Sopenharmony_ci	info->base		= base;
76362306a36Sopenharmony_ci	info->vaddr		= vaddr;
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci	mtd			= nand_to_mtd(&info->chip);
76662306a36Sopenharmony_ci	mtd->dev.parent		= &pdev->dev;
76762306a36Sopenharmony_ci	nand_set_flash_node(&info->chip, pdev->dev.of_node);
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci	/* options such as NAND_BBT_USE_FLASH */
77062306a36Sopenharmony_ci	info->chip.bbt_options	= pdata->bbt_options;
77162306a36Sopenharmony_ci	/* options such as 16-bit widths */
77262306a36Sopenharmony_ci	info->chip.options	= pdata->options;
77362306a36Sopenharmony_ci	info->chip.bbt_td	= pdata->bbt_td;
77462306a36Sopenharmony_ci	info->chip.bbt_md	= pdata->bbt_md;
77562306a36Sopenharmony_ci	info->timing		= pdata->timing;
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ci	info->current_cs	= info->vaddr;
77862306a36Sopenharmony_ci	info->core_chipsel	= pdata->core_chipsel;
77962306a36Sopenharmony_ci	info->mask_chipsel	= pdata->mask_chipsel;
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci	/* use nandboot-capable ALE/CLE masks by default */
78262306a36Sopenharmony_ci	info->mask_ale		= pdata->mask_ale ? : MASK_ALE;
78362306a36Sopenharmony_ci	info->mask_cle		= pdata->mask_cle ? : MASK_CLE;
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_ci	spin_lock_irq(&davinci_nand_lock);
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_ci	/* put CSxNAND into NAND mode */
78862306a36Sopenharmony_ci	val = davinci_nand_readl(info, NANDFCR_OFFSET);
78962306a36Sopenharmony_ci	val |= BIT(info->core_chipsel);
79062306a36Sopenharmony_ci	davinci_nand_writel(info, NANDFCR_OFFSET, val);
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci	spin_unlock_irq(&davinci_nand_lock);
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_ci	/* Scan to find existence of the device(s) */
79562306a36Sopenharmony_ci	nand_controller_init(&info->controller);
79662306a36Sopenharmony_ci	info->controller.ops = &davinci_nand_controller_ops;
79762306a36Sopenharmony_ci	info->chip.controller = &info->controller;
79862306a36Sopenharmony_ci	ret = nand_scan(&info->chip, pdata->mask_chipsel ? 2 : 1);
79962306a36Sopenharmony_ci	if (ret < 0) {
80062306a36Sopenharmony_ci		dev_dbg(&pdev->dev, "no NAND chip(s) found\n");
80162306a36Sopenharmony_ci		return ret;
80262306a36Sopenharmony_ci	}
80362306a36Sopenharmony_ci
80462306a36Sopenharmony_ci	if (pdata->parts)
80562306a36Sopenharmony_ci		ret = mtd_device_register(mtd, pdata->parts, pdata->nr_parts);
80662306a36Sopenharmony_ci	else
80762306a36Sopenharmony_ci		ret = mtd_device_register(mtd, NULL, 0);
80862306a36Sopenharmony_ci	if (ret < 0)
80962306a36Sopenharmony_ci		goto err_cleanup_nand;
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ci	val = davinci_nand_readl(info, NRCSR_OFFSET);
81262306a36Sopenharmony_ci	dev_info(&pdev->dev, "controller rev. %d.%d\n",
81362306a36Sopenharmony_ci	       (val >> 8) & 0xff, val & 0xff);
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_ci	return 0;
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_cierr_cleanup_nand:
81862306a36Sopenharmony_ci	nand_cleanup(&info->chip);
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_ci	return ret;
82162306a36Sopenharmony_ci}
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_cistatic void nand_davinci_remove(struct platform_device *pdev)
82462306a36Sopenharmony_ci{
82562306a36Sopenharmony_ci	struct davinci_nand_info *info = platform_get_drvdata(pdev);
82662306a36Sopenharmony_ci	struct nand_chip *chip = &info->chip;
82762306a36Sopenharmony_ci	int ret;
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci	spin_lock_irq(&davinci_nand_lock);
83062306a36Sopenharmony_ci	if (chip->ecc.placement == NAND_ECC_PLACEMENT_INTERLEAVED)
83162306a36Sopenharmony_ci		ecc4_busy = false;
83262306a36Sopenharmony_ci	spin_unlock_irq(&davinci_nand_lock);
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ci	ret = mtd_device_unregister(nand_to_mtd(chip));
83562306a36Sopenharmony_ci	WARN_ON(ret);
83662306a36Sopenharmony_ci	nand_cleanup(chip);
83762306a36Sopenharmony_ci}
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_cistatic struct platform_driver nand_davinci_driver = {
84062306a36Sopenharmony_ci	.probe		= nand_davinci_probe,
84162306a36Sopenharmony_ci	.remove_new	= nand_davinci_remove,
84262306a36Sopenharmony_ci	.driver		= {
84362306a36Sopenharmony_ci		.name	= "davinci_nand",
84462306a36Sopenharmony_ci		.of_match_table = of_match_ptr(davinci_nand_of_match),
84562306a36Sopenharmony_ci	},
84662306a36Sopenharmony_ci};
84762306a36Sopenharmony_ciMODULE_ALIAS("platform:davinci_nand");
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_cimodule_platform_driver(nand_davinci_driver);
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ciMODULE_LICENSE("GPL");
85262306a36Sopenharmony_ciMODULE_AUTHOR("Texas Instruments");
85362306a36Sopenharmony_ciMODULE_DESCRIPTION("Davinci NAND flash driver");
85462306a36Sopenharmony_ci
855