162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Arasan NAND Flash Controller Driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2014 - 2020 Xilinx, Inc.
662306a36Sopenharmony_ci * Author:
762306a36Sopenharmony_ci *   Miquel Raynal <miquel.raynal@bootlin.com>
862306a36Sopenharmony_ci * Original work (fully rewritten):
962306a36Sopenharmony_ci *   Punnaiah Choudary Kalluri <punnaia@xilinx.com>
1062306a36Sopenharmony_ci *   Naga Sureshkumar Relli <nagasure@xilinx.com>
1162306a36Sopenharmony_ci */
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include <linux/bch.h>
1462306a36Sopenharmony_ci#include <linux/bitfield.h>
1562306a36Sopenharmony_ci#include <linux/clk.h>
1662306a36Sopenharmony_ci#include <linux/delay.h>
1762306a36Sopenharmony_ci#include <linux/dma-mapping.h>
1862306a36Sopenharmony_ci#include <linux/gpio/consumer.h>
1962306a36Sopenharmony_ci#include <linux/interrupt.h>
2062306a36Sopenharmony_ci#include <linux/iopoll.h>
2162306a36Sopenharmony_ci#include <linux/module.h>
2262306a36Sopenharmony_ci#include <linux/mtd/mtd.h>
2362306a36Sopenharmony_ci#include <linux/mtd/partitions.h>
2462306a36Sopenharmony_ci#include <linux/mtd/rawnand.h>
2562306a36Sopenharmony_ci#include <linux/of.h>
2662306a36Sopenharmony_ci#include <linux/platform_device.h>
2762306a36Sopenharmony_ci#include <linux/slab.h>
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#define PKT_REG				0x00
3062306a36Sopenharmony_ci#define   PKT_SIZE(x)			FIELD_PREP(GENMASK(10, 0), (x))
3162306a36Sopenharmony_ci#define   PKT_STEPS(x)			FIELD_PREP(GENMASK(23, 12), (x))
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci#define MEM_ADDR1_REG			0x04
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci#define MEM_ADDR2_REG			0x08
3662306a36Sopenharmony_ci#define   ADDR2_STRENGTH(x)		FIELD_PREP(GENMASK(27, 25), (x))
3762306a36Sopenharmony_ci#define   ADDR2_CS(x)			FIELD_PREP(GENMASK(31, 30), (x))
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci#define CMD_REG				0x0C
4062306a36Sopenharmony_ci#define   CMD_1(x)			FIELD_PREP(GENMASK(7, 0), (x))
4162306a36Sopenharmony_ci#define   CMD_2(x)			FIELD_PREP(GENMASK(15, 8), (x))
4262306a36Sopenharmony_ci#define   CMD_PAGE_SIZE(x)		FIELD_PREP(GENMASK(25, 23), (x))
4362306a36Sopenharmony_ci#define   CMD_DMA_ENABLE		BIT(27)
4462306a36Sopenharmony_ci#define   CMD_NADDRS(x)			FIELD_PREP(GENMASK(30, 28), (x))
4562306a36Sopenharmony_ci#define   CMD_ECC_ENABLE		BIT(31)
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci#define PROG_REG			0x10
4862306a36Sopenharmony_ci#define   PROG_PGRD			BIT(0)
4962306a36Sopenharmony_ci#define   PROG_ERASE			BIT(2)
5062306a36Sopenharmony_ci#define   PROG_STATUS			BIT(3)
5162306a36Sopenharmony_ci#define   PROG_PGPROG			BIT(4)
5262306a36Sopenharmony_ci#define   PROG_RDID			BIT(6)
5362306a36Sopenharmony_ci#define   PROG_RDPARAM			BIT(7)
5462306a36Sopenharmony_ci#define   PROG_RST			BIT(8)
5562306a36Sopenharmony_ci#define   PROG_GET_FEATURE		BIT(9)
5662306a36Sopenharmony_ci#define   PROG_SET_FEATURE		BIT(10)
5762306a36Sopenharmony_ci#define   PROG_CHG_RD_COL_ENH		BIT(14)
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci#define INTR_STS_EN_REG			0x14
6062306a36Sopenharmony_ci#define INTR_SIG_EN_REG			0x18
6162306a36Sopenharmony_ci#define INTR_STS_REG			0x1C
6262306a36Sopenharmony_ci#define   WRITE_READY			BIT(0)
6362306a36Sopenharmony_ci#define   READ_READY			BIT(1)
6462306a36Sopenharmony_ci#define   XFER_COMPLETE			BIT(2)
6562306a36Sopenharmony_ci#define   DMA_BOUNDARY			BIT(6)
6662306a36Sopenharmony_ci#define   EVENT_MASK			GENMASK(7, 0)
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci#define READY_STS_REG			0x20
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci#define DMA_ADDR0_REG			0x50
7162306a36Sopenharmony_ci#define DMA_ADDR1_REG			0x24
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci#define FLASH_STS_REG			0x28
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci#define TIMING_REG			0x2C
7662306a36Sopenharmony_ci#define   TCCS_TIME_500NS		0
7762306a36Sopenharmony_ci#define   TCCS_TIME_300NS		3
7862306a36Sopenharmony_ci#define   TCCS_TIME_200NS		2
7962306a36Sopenharmony_ci#define   TCCS_TIME_100NS		1
8062306a36Sopenharmony_ci#define   FAST_TCAD			BIT(2)
8162306a36Sopenharmony_ci#define   DQS_BUFF_SEL_IN(x)		FIELD_PREP(GENMASK(6, 3), (x))
8262306a36Sopenharmony_ci#define   DQS_BUFF_SEL_OUT(x)		FIELD_PREP(GENMASK(18, 15), (x))
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci#define DATA_PORT_REG			0x30
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci#define ECC_CONF_REG			0x34
8762306a36Sopenharmony_ci#define   ECC_CONF_COL(x)		FIELD_PREP(GENMASK(15, 0), (x))
8862306a36Sopenharmony_ci#define   ECC_CONF_LEN(x)		FIELD_PREP(GENMASK(26, 16), (x))
8962306a36Sopenharmony_ci#define   ECC_CONF_BCH_EN		BIT(27)
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci#define ECC_ERR_CNT_REG			0x38
9262306a36Sopenharmony_ci#define   GET_PKT_ERR_CNT(x)		FIELD_GET(GENMASK(7, 0), (x))
9362306a36Sopenharmony_ci#define   GET_PAGE_ERR_CNT(x)		FIELD_GET(GENMASK(16, 8), (x))
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci#define ECC_SP_REG			0x3C
9662306a36Sopenharmony_ci#define   ECC_SP_CMD1(x)		FIELD_PREP(GENMASK(7, 0), (x))
9762306a36Sopenharmony_ci#define   ECC_SP_CMD2(x)		FIELD_PREP(GENMASK(15, 8), (x))
9862306a36Sopenharmony_ci#define   ECC_SP_ADDRS(x)		FIELD_PREP(GENMASK(30, 28), (x))
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci#define ECC_1ERR_CNT_REG		0x40
10162306a36Sopenharmony_ci#define ECC_2ERR_CNT_REG		0x44
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci#define DATA_INTERFACE_REG		0x6C
10462306a36Sopenharmony_ci#define   DIFACE_SDR_MODE(x)		FIELD_PREP(GENMASK(2, 0), (x))
10562306a36Sopenharmony_ci#define   DIFACE_DDR_MODE(x)		FIELD_PREP(GENMASK(5, 3), (x))
10662306a36Sopenharmony_ci#define   DIFACE_SDR			0
10762306a36Sopenharmony_ci#define   DIFACE_NVDDR			BIT(9)
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci#define ANFC_MAX_CS			2
11062306a36Sopenharmony_ci#define ANFC_DFLT_TIMEOUT_US		1000000
11162306a36Sopenharmony_ci#define ANFC_MAX_CHUNK_SIZE		SZ_1M
11262306a36Sopenharmony_ci#define ANFC_MAX_PARAM_SIZE		SZ_4K
11362306a36Sopenharmony_ci#define ANFC_MAX_STEPS			SZ_2K
11462306a36Sopenharmony_ci#define ANFC_MAX_PKT_SIZE		(SZ_2K - 1)
11562306a36Sopenharmony_ci#define ANFC_MAX_ADDR_CYC		5U
11662306a36Sopenharmony_ci#define ANFC_RSVD_ECC_BYTES		21
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci#define ANFC_XLNX_SDR_DFLT_CORE_CLK	100000000
11962306a36Sopenharmony_ci#define ANFC_XLNX_SDR_HS_CORE_CLK	80000000
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_cistatic struct gpio_desc *anfc_default_cs_array[2] = {NULL, NULL};
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci/**
12462306a36Sopenharmony_ci * struct anfc_op - Defines how to execute an operation
12562306a36Sopenharmony_ci * @pkt_reg: Packet register
12662306a36Sopenharmony_ci * @addr1_reg: Memory address 1 register
12762306a36Sopenharmony_ci * @addr2_reg: Memory address 2 register
12862306a36Sopenharmony_ci * @cmd_reg: Command register
12962306a36Sopenharmony_ci * @prog_reg: Program register
13062306a36Sopenharmony_ci * @steps: Number of "packets" to read/write
13162306a36Sopenharmony_ci * @rdy_timeout_ms: Timeout for waits on Ready/Busy pin
13262306a36Sopenharmony_ci * @len: Data transfer length
13362306a36Sopenharmony_ci * @read: Data transfer direction from the controller point of view
13462306a36Sopenharmony_ci * @buf: Data buffer
13562306a36Sopenharmony_ci */
13662306a36Sopenharmony_cistruct anfc_op {
13762306a36Sopenharmony_ci	u32 pkt_reg;
13862306a36Sopenharmony_ci	u32 addr1_reg;
13962306a36Sopenharmony_ci	u32 addr2_reg;
14062306a36Sopenharmony_ci	u32 cmd_reg;
14162306a36Sopenharmony_ci	u32 prog_reg;
14262306a36Sopenharmony_ci	int steps;
14362306a36Sopenharmony_ci	unsigned int rdy_timeout_ms;
14462306a36Sopenharmony_ci	unsigned int len;
14562306a36Sopenharmony_ci	bool read;
14662306a36Sopenharmony_ci	u8 *buf;
14762306a36Sopenharmony_ci};
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci/**
15062306a36Sopenharmony_ci * struct anand - Defines the NAND chip related information
15162306a36Sopenharmony_ci * @node:		Used to store NAND chips into a list
15262306a36Sopenharmony_ci * @chip:		NAND chip information structure
15362306a36Sopenharmony_ci * @rb:			Ready-busy line
15462306a36Sopenharmony_ci * @page_sz:		Register value of the page_sz field to use
15562306a36Sopenharmony_ci * @clk:		Expected clock frequency to use
15662306a36Sopenharmony_ci * @data_iface:		Data interface timing mode to use
15762306a36Sopenharmony_ci * @timings:		NV-DDR specific timings to use
15862306a36Sopenharmony_ci * @ecc_conf:		Hardware ECC configuration value
15962306a36Sopenharmony_ci * @strength:		Register value of the ECC strength
16062306a36Sopenharmony_ci * @raddr_cycles:	Row address cycle information
16162306a36Sopenharmony_ci * @caddr_cycles:	Column address cycle information
16262306a36Sopenharmony_ci * @ecc_bits:		Exact number of ECC bits per syndrome
16362306a36Sopenharmony_ci * @ecc_total:		Total number of ECC bytes
16462306a36Sopenharmony_ci * @errloc:		Array of errors located with soft BCH
16562306a36Sopenharmony_ci * @hw_ecc:		Buffer to store syndromes computed by hardware
16662306a36Sopenharmony_ci * @bch:		BCH structure
16762306a36Sopenharmony_ci * @cs_idx:		Array of chip-select for this device, values are indexes
16862306a36Sopenharmony_ci *			of the controller structure @gpio_cs array
16962306a36Sopenharmony_ci * @ncs_idx:		Size of the @cs_idx array
17062306a36Sopenharmony_ci */
17162306a36Sopenharmony_cistruct anand {
17262306a36Sopenharmony_ci	struct list_head node;
17362306a36Sopenharmony_ci	struct nand_chip chip;
17462306a36Sopenharmony_ci	unsigned int rb;
17562306a36Sopenharmony_ci	unsigned int page_sz;
17662306a36Sopenharmony_ci	unsigned long clk;
17762306a36Sopenharmony_ci	u32 data_iface;
17862306a36Sopenharmony_ci	u32 timings;
17962306a36Sopenharmony_ci	u32 ecc_conf;
18062306a36Sopenharmony_ci	u32 strength;
18162306a36Sopenharmony_ci	u16 raddr_cycles;
18262306a36Sopenharmony_ci	u16 caddr_cycles;
18362306a36Sopenharmony_ci	unsigned int ecc_bits;
18462306a36Sopenharmony_ci	unsigned int ecc_total;
18562306a36Sopenharmony_ci	unsigned int *errloc;
18662306a36Sopenharmony_ci	u8 *hw_ecc;
18762306a36Sopenharmony_ci	struct bch_control *bch;
18862306a36Sopenharmony_ci	int *cs_idx;
18962306a36Sopenharmony_ci	int ncs_idx;
19062306a36Sopenharmony_ci};
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci/**
19362306a36Sopenharmony_ci * struct arasan_nfc - Defines the Arasan NAND flash controller driver instance
19462306a36Sopenharmony_ci * @dev:		Pointer to the device structure
19562306a36Sopenharmony_ci * @base:		Remapped register area
19662306a36Sopenharmony_ci * @controller_clk:		Pointer to the system clock
19762306a36Sopenharmony_ci * @bus_clk:		Pointer to the flash clock
19862306a36Sopenharmony_ci * @controller:		Base controller structure
19962306a36Sopenharmony_ci * @chips:		List of all NAND chips attached to the controller
20062306a36Sopenharmony_ci * @cur_clk:		Current clock rate
20162306a36Sopenharmony_ci * @cs_array:		CS array. Native CS are left empty, the other cells are
20262306a36Sopenharmony_ci *			populated with their corresponding GPIO descriptor.
20362306a36Sopenharmony_ci * @ncs:		Size of @cs_array
20462306a36Sopenharmony_ci * @cur_cs:		Index in @cs_array of the currently in use CS
20562306a36Sopenharmony_ci * @native_cs:		Currently selected native CS
20662306a36Sopenharmony_ci * @spare_cs:		Native CS that is not wired (may be selected when a GPIO
20762306a36Sopenharmony_ci *			CS is in use)
20862306a36Sopenharmony_ci */
20962306a36Sopenharmony_cistruct arasan_nfc {
21062306a36Sopenharmony_ci	struct device *dev;
21162306a36Sopenharmony_ci	void __iomem *base;
21262306a36Sopenharmony_ci	struct clk *controller_clk;
21362306a36Sopenharmony_ci	struct clk *bus_clk;
21462306a36Sopenharmony_ci	struct nand_controller controller;
21562306a36Sopenharmony_ci	struct list_head chips;
21662306a36Sopenharmony_ci	unsigned int cur_clk;
21762306a36Sopenharmony_ci	struct gpio_desc **cs_array;
21862306a36Sopenharmony_ci	unsigned int ncs;
21962306a36Sopenharmony_ci	int cur_cs;
22062306a36Sopenharmony_ci	unsigned int native_cs;
22162306a36Sopenharmony_ci	unsigned int spare_cs;
22262306a36Sopenharmony_ci};
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_cistatic struct anand *to_anand(struct nand_chip *nand)
22562306a36Sopenharmony_ci{
22662306a36Sopenharmony_ci	return container_of(nand, struct anand, chip);
22762306a36Sopenharmony_ci}
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_cistatic struct arasan_nfc *to_anfc(struct nand_controller *ctrl)
23062306a36Sopenharmony_ci{
23162306a36Sopenharmony_ci	return container_of(ctrl, struct arasan_nfc, controller);
23262306a36Sopenharmony_ci}
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_cistatic int anfc_wait_for_event(struct arasan_nfc *nfc, unsigned int event)
23562306a36Sopenharmony_ci{
23662306a36Sopenharmony_ci	u32 val;
23762306a36Sopenharmony_ci	int ret;
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	ret = readl_relaxed_poll_timeout(nfc->base + INTR_STS_REG, val,
24062306a36Sopenharmony_ci					 val & event, 0,
24162306a36Sopenharmony_ci					 ANFC_DFLT_TIMEOUT_US);
24262306a36Sopenharmony_ci	if (ret) {
24362306a36Sopenharmony_ci		dev_err(nfc->dev, "Timeout waiting for event 0x%x\n", event);
24462306a36Sopenharmony_ci		return -ETIMEDOUT;
24562306a36Sopenharmony_ci	}
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	writel_relaxed(event, nfc->base + INTR_STS_REG);
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	return 0;
25062306a36Sopenharmony_ci}
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_cistatic int anfc_wait_for_rb(struct arasan_nfc *nfc, struct nand_chip *chip,
25362306a36Sopenharmony_ci			    unsigned int timeout_ms)
25462306a36Sopenharmony_ci{
25562306a36Sopenharmony_ci	struct anand *anand = to_anand(chip);
25662306a36Sopenharmony_ci	u32 val;
25762306a36Sopenharmony_ci	int ret;
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	/* There is no R/B interrupt, we must poll a register */
26062306a36Sopenharmony_ci	ret = readl_relaxed_poll_timeout(nfc->base + READY_STS_REG, val,
26162306a36Sopenharmony_ci					 val & BIT(anand->rb),
26262306a36Sopenharmony_ci					 1, timeout_ms * 1000);
26362306a36Sopenharmony_ci	if (ret) {
26462306a36Sopenharmony_ci		dev_err(nfc->dev, "Timeout waiting for R/B 0x%x\n",
26562306a36Sopenharmony_ci			readl_relaxed(nfc->base + READY_STS_REG));
26662306a36Sopenharmony_ci		return -ETIMEDOUT;
26762306a36Sopenharmony_ci	}
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	return 0;
27062306a36Sopenharmony_ci}
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_cistatic void anfc_trigger_op(struct arasan_nfc *nfc, struct anfc_op *nfc_op)
27362306a36Sopenharmony_ci{
27462306a36Sopenharmony_ci	writel_relaxed(nfc_op->pkt_reg, nfc->base + PKT_REG);
27562306a36Sopenharmony_ci	writel_relaxed(nfc_op->addr1_reg, nfc->base + MEM_ADDR1_REG);
27662306a36Sopenharmony_ci	writel_relaxed(nfc_op->addr2_reg, nfc->base + MEM_ADDR2_REG);
27762306a36Sopenharmony_ci	writel_relaxed(nfc_op->cmd_reg, nfc->base + CMD_REG);
27862306a36Sopenharmony_ci	writel_relaxed(nfc_op->prog_reg, nfc->base + PROG_REG);
27962306a36Sopenharmony_ci}
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_cistatic int anfc_pkt_len_config(unsigned int len, unsigned int *steps,
28262306a36Sopenharmony_ci			       unsigned int *pktsize)
28362306a36Sopenharmony_ci{
28462306a36Sopenharmony_ci	unsigned int nb, sz;
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	for (nb = 1; nb < ANFC_MAX_STEPS; nb *= 2) {
28762306a36Sopenharmony_ci		sz = len / nb;
28862306a36Sopenharmony_ci		if (sz <= ANFC_MAX_PKT_SIZE)
28962306a36Sopenharmony_ci			break;
29062306a36Sopenharmony_ci	}
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	if (sz * nb != len)
29362306a36Sopenharmony_ci		return -ENOTSUPP;
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	if (steps)
29662306a36Sopenharmony_ci		*steps = nb;
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	if (pktsize)
29962306a36Sopenharmony_ci		*pktsize = sz;
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	return 0;
30262306a36Sopenharmony_ci}
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_cistatic bool anfc_is_gpio_cs(struct arasan_nfc *nfc, int nfc_cs)
30562306a36Sopenharmony_ci{
30662306a36Sopenharmony_ci	return nfc_cs >= 0 && nfc->cs_array[nfc_cs];
30762306a36Sopenharmony_ci}
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_cistatic int anfc_relative_to_absolute_cs(struct anand *anand, int num)
31062306a36Sopenharmony_ci{
31162306a36Sopenharmony_ci	return anand->cs_idx[num];
31262306a36Sopenharmony_ci}
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_cistatic void anfc_assert_cs(struct arasan_nfc *nfc, unsigned int nfc_cs_idx)
31562306a36Sopenharmony_ci{
31662306a36Sopenharmony_ci	/* CS did not change: do nothing */
31762306a36Sopenharmony_ci	if (nfc->cur_cs == nfc_cs_idx)
31862306a36Sopenharmony_ci		return;
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	/* Deassert the previous CS if it was a GPIO */
32162306a36Sopenharmony_ci	if (anfc_is_gpio_cs(nfc, nfc->cur_cs))
32262306a36Sopenharmony_ci		gpiod_set_value_cansleep(nfc->cs_array[nfc->cur_cs], 1);
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	/* Assert the new one */
32562306a36Sopenharmony_ci	if (anfc_is_gpio_cs(nfc, nfc_cs_idx)) {
32662306a36Sopenharmony_ci		nfc->native_cs = nfc->spare_cs;
32762306a36Sopenharmony_ci		gpiod_set_value_cansleep(nfc->cs_array[nfc_cs_idx], 0);
32862306a36Sopenharmony_ci	} else {
32962306a36Sopenharmony_ci		nfc->native_cs = nfc_cs_idx;
33062306a36Sopenharmony_ci	}
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	nfc->cur_cs = nfc_cs_idx;
33362306a36Sopenharmony_ci}
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_cistatic int anfc_select_target(struct nand_chip *chip, int target)
33662306a36Sopenharmony_ci{
33762306a36Sopenharmony_ci	struct anand *anand = to_anand(chip);
33862306a36Sopenharmony_ci	struct arasan_nfc *nfc = to_anfc(chip->controller);
33962306a36Sopenharmony_ci	unsigned int nfc_cs_idx = anfc_relative_to_absolute_cs(anand, target);
34062306a36Sopenharmony_ci	int ret;
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	anfc_assert_cs(nfc, nfc_cs_idx);
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	/* Update the controller timings and the potential ECC configuration */
34562306a36Sopenharmony_ci	writel_relaxed(anand->data_iface, nfc->base + DATA_INTERFACE_REG);
34662306a36Sopenharmony_ci	writel_relaxed(anand->timings, nfc->base + TIMING_REG);
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	/* Update clock frequency */
34962306a36Sopenharmony_ci	if (nfc->cur_clk != anand->clk) {
35062306a36Sopenharmony_ci		clk_disable_unprepare(nfc->bus_clk);
35162306a36Sopenharmony_ci		ret = clk_set_rate(nfc->bus_clk, anand->clk);
35262306a36Sopenharmony_ci		if (ret) {
35362306a36Sopenharmony_ci			dev_err(nfc->dev, "Failed to change clock rate\n");
35462306a36Sopenharmony_ci			return ret;
35562306a36Sopenharmony_ci		}
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci		ret = clk_prepare_enable(nfc->bus_clk);
35862306a36Sopenharmony_ci		if (ret) {
35962306a36Sopenharmony_ci			dev_err(nfc->dev,
36062306a36Sopenharmony_ci				"Failed to re-enable the bus clock\n");
36162306a36Sopenharmony_ci			return ret;
36262306a36Sopenharmony_ci		}
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci		nfc->cur_clk = anand->clk;
36562306a36Sopenharmony_ci	}
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	return 0;
36862306a36Sopenharmony_ci}
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci/*
37162306a36Sopenharmony_ci * When using the embedded hardware ECC engine, the controller is in charge of
37262306a36Sopenharmony_ci * feeding the engine with, first, the ECC residue present in the data array.
37362306a36Sopenharmony_ci * A typical read operation is:
37462306a36Sopenharmony_ci * 1/ Assert the read operation by sending the relevant command/address cycles
37562306a36Sopenharmony_ci *    but targeting the column of the first ECC bytes in the OOB area instead of
37662306a36Sopenharmony_ci *    the main data directly.
37762306a36Sopenharmony_ci * 2/ After having read the relevant number of ECC bytes, the controller uses
37862306a36Sopenharmony_ci *    the RNDOUT/RNDSTART commands which are set into the "ECC Spare Command
37962306a36Sopenharmony_ci *    Register" to move the pointer back at the beginning of the main data.
38062306a36Sopenharmony_ci * 3/ It will read the content of the main area for a given size (pktsize) and
38162306a36Sopenharmony_ci *    will feed the ECC engine with this buffer again.
38262306a36Sopenharmony_ci * 4/ The ECC engine derives the ECC bytes for the given data and compare them
38362306a36Sopenharmony_ci *    with the ones already received. It eventually trigger status flags and
38462306a36Sopenharmony_ci *    then set the "Buffer Read Ready" flag.
38562306a36Sopenharmony_ci * 5/ The corrected data is then available for reading from the data port
38662306a36Sopenharmony_ci *    register.
38762306a36Sopenharmony_ci *
38862306a36Sopenharmony_ci * The hardware BCH ECC engine is known to be inconstent in BCH mode and never
38962306a36Sopenharmony_ci * reports uncorrectable errors. Because of this bug, we have to use the
39062306a36Sopenharmony_ci * software BCH implementation in the read path.
39162306a36Sopenharmony_ci */
39262306a36Sopenharmony_cistatic int anfc_read_page_hw_ecc(struct nand_chip *chip, u8 *buf,
39362306a36Sopenharmony_ci				 int oob_required, int page)
39462306a36Sopenharmony_ci{
39562306a36Sopenharmony_ci	struct arasan_nfc *nfc = to_anfc(chip->controller);
39662306a36Sopenharmony_ci	struct mtd_info *mtd = nand_to_mtd(chip);
39762306a36Sopenharmony_ci	struct anand *anand = to_anand(chip);
39862306a36Sopenharmony_ci	unsigned int len = mtd->writesize + (oob_required ? mtd->oobsize : 0);
39962306a36Sopenharmony_ci	unsigned int max_bitflips = 0;
40062306a36Sopenharmony_ci	dma_addr_t dma_addr;
40162306a36Sopenharmony_ci	int step, ret;
40262306a36Sopenharmony_ci	struct anfc_op nfc_op = {
40362306a36Sopenharmony_ci		.pkt_reg =
40462306a36Sopenharmony_ci			PKT_SIZE(chip->ecc.size) |
40562306a36Sopenharmony_ci			PKT_STEPS(chip->ecc.steps),
40662306a36Sopenharmony_ci		.addr1_reg =
40762306a36Sopenharmony_ci			(page & 0xFF) << (8 * (anand->caddr_cycles)) |
40862306a36Sopenharmony_ci			(((page >> 8) & 0xFF) << (8 * (1 + anand->caddr_cycles))),
40962306a36Sopenharmony_ci		.addr2_reg =
41062306a36Sopenharmony_ci			((page >> 16) & 0xFF) |
41162306a36Sopenharmony_ci			ADDR2_STRENGTH(anand->strength) |
41262306a36Sopenharmony_ci			ADDR2_CS(nfc->native_cs),
41362306a36Sopenharmony_ci		.cmd_reg =
41462306a36Sopenharmony_ci			CMD_1(NAND_CMD_READ0) |
41562306a36Sopenharmony_ci			CMD_2(NAND_CMD_READSTART) |
41662306a36Sopenharmony_ci			CMD_PAGE_SIZE(anand->page_sz) |
41762306a36Sopenharmony_ci			CMD_DMA_ENABLE |
41862306a36Sopenharmony_ci			CMD_NADDRS(anand->caddr_cycles +
41962306a36Sopenharmony_ci				   anand->raddr_cycles),
42062306a36Sopenharmony_ci		.prog_reg = PROG_PGRD,
42162306a36Sopenharmony_ci	};
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	dma_addr = dma_map_single(nfc->dev, (void *)buf, len, DMA_FROM_DEVICE);
42462306a36Sopenharmony_ci	if (dma_mapping_error(nfc->dev, dma_addr)) {
42562306a36Sopenharmony_ci		dev_err(nfc->dev, "Buffer mapping error");
42662306a36Sopenharmony_ci		return -EIO;
42762306a36Sopenharmony_ci	}
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	writel_relaxed(lower_32_bits(dma_addr), nfc->base + DMA_ADDR0_REG);
43062306a36Sopenharmony_ci	writel_relaxed(upper_32_bits(dma_addr), nfc->base + DMA_ADDR1_REG);
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	anfc_trigger_op(nfc, &nfc_op);
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	ret = anfc_wait_for_event(nfc, XFER_COMPLETE);
43562306a36Sopenharmony_ci	dma_unmap_single(nfc->dev, dma_addr, len, DMA_FROM_DEVICE);
43662306a36Sopenharmony_ci	if (ret) {
43762306a36Sopenharmony_ci		dev_err(nfc->dev, "Error reading page %d\n", page);
43862306a36Sopenharmony_ci		return ret;
43962306a36Sopenharmony_ci	}
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	/* Store the raw OOB bytes as well */
44262306a36Sopenharmony_ci	ret = nand_change_read_column_op(chip, mtd->writesize, chip->oob_poi,
44362306a36Sopenharmony_ci					 mtd->oobsize, 0);
44462306a36Sopenharmony_ci	if (ret)
44562306a36Sopenharmony_ci		return ret;
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci	/*
44862306a36Sopenharmony_ci	 * For each step, compute by softare the BCH syndrome over the raw data.
44962306a36Sopenharmony_ci	 * Compare the theoretical amount of errors and compare with the
45062306a36Sopenharmony_ci	 * hardware engine feedback.
45162306a36Sopenharmony_ci	 */
45262306a36Sopenharmony_ci	for (step = 0; step < chip->ecc.steps; step++) {
45362306a36Sopenharmony_ci		u8 *raw_buf = &buf[step * chip->ecc.size];
45462306a36Sopenharmony_ci		unsigned int bit, byte;
45562306a36Sopenharmony_ci		int bf, i;
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci		/* Extract the syndrome, it is not necessarily aligned */
45862306a36Sopenharmony_ci		memset(anand->hw_ecc, 0, chip->ecc.bytes);
45962306a36Sopenharmony_ci		nand_extract_bits(anand->hw_ecc, 0,
46062306a36Sopenharmony_ci				  &chip->oob_poi[mtd->oobsize - anand->ecc_total],
46162306a36Sopenharmony_ci				  anand->ecc_bits * step, anand->ecc_bits);
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci		bf = bch_decode(anand->bch, raw_buf, chip->ecc.size,
46462306a36Sopenharmony_ci				anand->hw_ecc, NULL, NULL, anand->errloc);
46562306a36Sopenharmony_ci		if (!bf) {
46662306a36Sopenharmony_ci			continue;
46762306a36Sopenharmony_ci		} else if (bf > 0) {
46862306a36Sopenharmony_ci			for (i = 0; i < bf; i++) {
46962306a36Sopenharmony_ci				/* Only correct the data, not the syndrome */
47062306a36Sopenharmony_ci				if (anand->errloc[i] < (chip->ecc.size * 8)) {
47162306a36Sopenharmony_ci					bit = BIT(anand->errloc[i] & 7);
47262306a36Sopenharmony_ci					byte = anand->errloc[i] >> 3;
47362306a36Sopenharmony_ci					raw_buf[byte] ^= bit;
47462306a36Sopenharmony_ci				}
47562306a36Sopenharmony_ci			}
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci			mtd->ecc_stats.corrected += bf;
47862306a36Sopenharmony_ci			max_bitflips = max_t(unsigned int, max_bitflips, bf);
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci			continue;
48162306a36Sopenharmony_ci		}
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci		bf = nand_check_erased_ecc_chunk(raw_buf, chip->ecc.size,
48462306a36Sopenharmony_ci						 NULL, 0, NULL, 0,
48562306a36Sopenharmony_ci						 chip->ecc.strength);
48662306a36Sopenharmony_ci		if (bf > 0) {
48762306a36Sopenharmony_ci			mtd->ecc_stats.corrected += bf;
48862306a36Sopenharmony_ci			max_bitflips = max_t(unsigned int, max_bitflips, bf);
48962306a36Sopenharmony_ci			memset(raw_buf, 0xFF, chip->ecc.size);
49062306a36Sopenharmony_ci		} else if (bf < 0) {
49162306a36Sopenharmony_ci			mtd->ecc_stats.failed++;
49262306a36Sopenharmony_ci		}
49362306a36Sopenharmony_ci	}
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci	return 0;
49662306a36Sopenharmony_ci}
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_cistatic int anfc_sel_read_page_hw_ecc(struct nand_chip *chip, u8 *buf,
49962306a36Sopenharmony_ci				     int oob_required, int page)
50062306a36Sopenharmony_ci{
50162306a36Sopenharmony_ci	int ret;
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci	ret = anfc_select_target(chip, chip->cur_cs);
50462306a36Sopenharmony_ci	if (ret)
50562306a36Sopenharmony_ci		return ret;
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	return anfc_read_page_hw_ecc(chip, buf, oob_required, page);
50862306a36Sopenharmony_ci};
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_cistatic int anfc_write_page_hw_ecc(struct nand_chip *chip, const u8 *buf,
51162306a36Sopenharmony_ci				  int oob_required, int page)
51262306a36Sopenharmony_ci{
51362306a36Sopenharmony_ci	struct anand *anand = to_anand(chip);
51462306a36Sopenharmony_ci	struct arasan_nfc *nfc = to_anfc(chip->controller);
51562306a36Sopenharmony_ci	struct mtd_info *mtd = nand_to_mtd(chip);
51662306a36Sopenharmony_ci	unsigned int len = mtd->writesize + (oob_required ? mtd->oobsize : 0);
51762306a36Sopenharmony_ci	dma_addr_t dma_addr;
51862306a36Sopenharmony_ci	u8 status;
51962306a36Sopenharmony_ci	int ret;
52062306a36Sopenharmony_ci	struct anfc_op nfc_op = {
52162306a36Sopenharmony_ci		.pkt_reg =
52262306a36Sopenharmony_ci			PKT_SIZE(chip->ecc.size) |
52362306a36Sopenharmony_ci			PKT_STEPS(chip->ecc.steps),
52462306a36Sopenharmony_ci		.addr1_reg =
52562306a36Sopenharmony_ci			(page & 0xFF) << (8 * (anand->caddr_cycles)) |
52662306a36Sopenharmony_ci			(((page >> 8) & 0xFF) << (8 * (1 + anand->caddr_cycles))),
52762306a36Sopenharmony_ci		.addr2_reg =
52862306a36Sopenharmony_ci			((page >> 16) & 0xFF) |
52962306a36Sopenharmony_ci			ADDR2_STRENGTH(anand->strength) |
53062306a36Sopenharmony_ci			ADDR2_CS(nfc->native_cs),
53162306a36Sopenharmony_ci		.cmd_reg =
53262306a36Sopenharmony_ci			CMD_1(NAND_CMD_SEQIN) |
53362306a36Sopenharmony_ci			CMD_2(NAND_CMD_PAGEPROG) |
53462306a36Sopenharmony_ci			CMD_PAGE_SIZE(anand->page_sz) |
53562306a36Sopenharmony_ci			CMD_DMA_ENABLE |
53662306a36Sopenharmony_ci			CMD_NADDRS(anand->caddr_cycles +
53762306a36Sopenharmony_ci				   anand->raddr_cycles) |
53862306a36Sopenharmony_ci			CMD_ECC_ENABLE,
53962306a36Sopenharmony_ci		.prog_reg = PROG_PGPROG,
54062306a36Sopenharmony_ci	};
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci	writel_relaxed(anand->ecc_conf, nfc->base + ECC_CONF_REG);
54362306a36Sopenharmony_ci	writel_relaxed(ECC_SP_CMD1(NAND_CMD_RNDIN) |
54462306a36Sopenharmony_ci		       ECC_SP_ADDRS(anand->caddr_cycles),
54562306a36Sopenharmony_ci		       nfc->base + ECC_SP_REG);
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci	dma_addr = dma_map_single(nfc->dev, (void *)buf, len, DMA_TO_DEVICE);
54862306a36Sopenharmony_ci	if (dma_mapping_error(nfc->dev, dma_addr)) {
54962306a36Sopenharmony_ci		dev_err(nfc->dev, "Buffer mapping error");
55062306a36Sopenharmony_ci		return -EIO;
55162306a36Sopenharmony_ci	}
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci	writel_relaxed(lower_32_bits(dma_addr), nfc->base + DMA_ADDR0_REG);
55462306a36Sopenharmony_ci	writel_relaxed(upper_32_bits(dma_addr), nfc->base + DMA_ADDR1_REG);
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci	anfc_trigger_op(nfc, &nfc_op);
55762306a36Sopenharmony_ci	ret = anfc_wait_for_event(nfc, XFER_COMPLETE);
55862306a36Sopenharmony_ci	dma_unmap_single(nfc->dev, dma_addr, len, DMA_TO_DEVICE);
55962306a36Sopenharmony_ci	if (ret) {
56062306a36Sopenharmony_ci		dev_err(nfc->dev, "Error writing page %d\n", page);
56162306a36Sopenharmony_ci		return ret;
56262306a36Sopenharmony_ci	}
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci	/* Spare data is not protected */
56562306a36Sopenharmony_ci	if (oob_required) {
56662306a36Sopenharmony_ci		ret = nand_write_oob_std(chip, page);
56762306a36Sopenharmony_ci		if (ret)
56862306a36Sopenharmony_ci			return ret;
56962306a36Sopenharmony_ci	}
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci	/* Check write status on the chip side */
57262306a36Sopenharmony_ci	ret = nand_status_op(chip, &status);
57362306a36Sopenharmony_ci	if (ret)
57462306a36Sopenharmony_ci		return ret;
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci	if (status & NAND_STATUS_FAIL)
57762306a36Sopenharmony_ci		return -EIO;
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci	return 0;
58062306a36Sopenharmony_ci}
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_cistatic int anfc_sel_write_page_hw_ecc(struct nand_chip *chip, const u8 *buf,
58362306a36Sopenharmony_ci				      int oob_required, int page)
58462306a36Sopenharmony_ci{
58562306a36Sopenharmony_ci	int ret;
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	ret = anfc_select_target(chip, chip->cur_cs);
58862306a36Sopenharmony_ci	if (ret)
58962306a36Sopenharmony_ci		return ret;
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	return anfc_write_page_hw_ecc(chip, buf, oob_required, page);
59262306a36Sopenharmony_ci};
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci/* NAND framework ->exec_op() hooks and related helpers */
59562306a36Sopenharmony_cistatic int anfc_parse_instructions(struct nand_chip *chip,
59662306a36Sopenharmony_ci				   const struct nand_subop *subop,
59762306a36Sopenharmony_ci				   struct anfc_op *nfc_op)
59862306a36Sopenharmony_ci{
59962306a36Sopenharmony_ci	struct arasan_nfc *nfc = to_anfc(chip->controller);
60062306a36Sopenharmony_ci	struct anand *anand = to_anand(chip);
60162306a36Sopenharmony_ci	const struct nand_op_instr *instr = NULL;
60262306a36Sopenharmony_ci	bool first_cmd = true;
60362306a36Sopenharmony_ci	unsigned int op_id;
60462306a36Sopenharmony_ci	int ret, i;
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci	memset(nfc_op, 0, sizeof(*nfc_op));
60762306a36Sopenharmony_ci	nfc_op->addr2_reg = ADDR2_CS(nfc->native_cs);
60862306a36Sopenharmony_ci	nfc_op->cmd_reg = CMD_PAGE_SIZE(anand->page_sz);
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci	for (op_id = 0; op_id < subop->ninstrs; op_id++) {
61162306a36Sopenharmony_ci		unsigned int offset, naddrs, pktsize;
61262306a36Sopenharmony_ci		const u8 *addrs;
61362306a36Sopenharmony_ci		u8 *buf;
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci		instr = &subop->instrs[op_id];
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci		switch (instr->type) {
61862306a36Sopenharmony_ci		case NAND_OP_CMD_INSTR:
61962306a36Sopenharmony_ci			if (first_cmd)
62062306a36Sopenharmony_ci				nfc_op->cmd_reg |= CMD_1(instr->ctx.cmd.opcode);
62162306a36Sopenharmony_ci			else
62262306a36Sopenharmony_ci				nfc_op->cmd_reg |= CMD_2(instr->ctx.cmd.opcode);
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci			first_cmd = false;
62562306a36Sopenharmony_ci			break;
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci		case NAND_OP_ADDR_INSTR:
62862306a36Sopenharmony_ci			offset = nand_subop_get_addr_start_off(subop, op_id);
62962306a36Sopenharmony_ci			naddrs = nand_subop_get_num_addr_cyc(subop, op_id);
63062306a36Sopenharmony_ci			addrs = &instr->ctx.addr.addrs[offset];
63162306a36Sopenharmony_ci			nfc_op->cmd_reg |= CMD_NADDRS(naddrs);
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci			for (i = 0; i < min(ANFC_MAX_ADDR_CYC, naddrs); i++) {
63462306a36Sopenharmony_ci				if (i < 4)
63562306a36Sopenharmony_ci					nfc_op->addr1_reg |= (u32)addrs[i] << i * 8;
63662306a36Sopenharmony_ci				else
63762306a36Sopenharmony_ci					nfc_op->addr2_reg |= addrs[i];
63862306a36Sopenharmony_ci			}
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci			break;
64162306a36Sopenharmony_ci		case NAND_OP_DATA_IN_INSTR:
64262306a36Sopenharmony_ci			nfc_op->read = true;
64362306a36Sopenharmony_ci			fallthrough;
64462306a36Sopenharmony_ci		case NAND_OP_DATA_OUT_INSTR:
64562306a36Sopenharmony_ci			offset = nand_subop_get_data_start_off(subop, op_id);
64662306a36Sopenharmony_ci			buf = instr->ctx.data.buf.in;
64762306a36Sopenharmony_ci			nfc_op->buf = &buf[offset];
64862306a36Sopenharmony_ci			nfc_op->len = nand_subop_get_data_len(subop, op_id);
64962306a36Sopenharmony_ci			ret = anfc_pkt_len_config(nfc_op->len, &nfc_op->steps,
65062306a36Sopenharmony_ci						  &pktsize);
65162306a36Sopenharmony_ci			if (ret)
65262306a36Sopenharmony_ci				return ret;
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci			/*
65562306a36Sopenharmony_ci			 * Number of DATA cycles must be aligned on 4, this
65662306a36Sopenharmony_ci			 * means the controller might read/write more than
65762306a36Sopenharmony_ci			 * requested. This is harmless most of the time as extra
65862306a36Sopenharmony_ci			 * DATA are discarded in the write path and read pointer
65962306a36Sopenharmony_ci			 * adjusted in the read path.
66062306a36Sopenharmony_ci			 *
66162306a36Sopenharmony_ci			 * FIXME: The core should mark operations where
66262306a36Sopenharmony_ci			 * reading/writing more is allowed so the exec_op()
66362306a36Sopenharmony_ci			 * implementation can take the right decision when the
66462306a36Sopenharmony_ci			 * alignment constraint is not met: adjust the number of
66562306a36Sopenharmony_ci			 * DATA cycles when it's allowed, reject the operation
66662306a36Sopenharmony_ci			 * otherwise.
66762306a36Sopenharmony_ci			 */
66862306a36Sopenharmony_ci			nfc_op->pkt_reg |= PKT_SIZE(round_up(pktsize, 4)) |
66962306a36Sopenharmony_ci					   PKT_STEPS(nfc_op->steps);
67062306a36Sopenharmony_ci			break;
67162306a36Sopenharmony_ci		case NAND_OP_WAITRDY_INSTR:
67262306a36Sopenharmony_ci			nfc_op->rdy_timeout_ms = instr->ctx.waitrdy.timeout_ms;
67362306a36Sopenharmony_ci			break;
67462306a36Sopenharmony_ci		}
67562306a36Sopenharmony_ci	}
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ci	return 0;
67862306a36Sopenharmony_ci}
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_cistatic int anfc_rw_pio_op(struct arasan_nfc *nfc, struct anfc_op *nfc_op)
68162306a36Sopenharmony_ci{
68262306a36Sopenharmony_ci	unsigned int dwords = (nfc_op->len / 4) / nfc_op->steps;
68362306a36Sopenharmony_ci	unsigned int last_len = nfc_op->len % 4;
68462306a36Sopenharmony_ci	unsigned int offset, dir;
68562306a36Sopenharmony_ci	u8 *buf = nfc_op->buf;
68662306a36Sopenharmony_ci	int ret, i;
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci	for (i = 0; i < nfc_op->steps; i++) {
68962306a36Sopenharmony_ci		dir = nfc_op->read ? READ_READY : WRITE_READY;
69062306a36Sopenharmony_ci		ret = anfc_wait_for_event(nfc, dir);
69162306a36Sopenharmony_ci		if (ret) {
69262306a36Sopenharmony_ci			dev_err(nfc->dev, "PIO %s ready signal not received\n",
69362306a36Sopenharmony_ci				nfc_op->read ? "Read" : "Write");
69462306a36Sopenharmony_ci			return ret;
69562306a36Sopenharmony_ci		}
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ci		offset = i * (dwords * 4);
69862306a36Sopenharmony_ci		if (nfc_op->read)
69962306a36Sopenharmony_ci			ioread32_rep(nfc->base + DATA_PORT_REG, &buf[offset],
70062306a36Sopenharmony_ci				     dwords);
70162306a36Sopenharmony_ci		else
70262306a36Sopenharmony_ci			iowrite32_rep(nfc->base + DATA_PORT_REG, &buf[offset],
70362306a36Sopenharmony_ci				      dwords);
70462306a36Sopenharmony_ci	}
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci	if (last_len) {
70762306a36Sopenharmony_ci		u32 remainder;
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci		offset = nfc_op->len - last_len;
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci		if (nfc_op->read) {
71262306a36Sopenharmony_ci			remainder = readl_relaxed(nfc->base + DATA_PORT_REG);
71362306a36Sopenharmony_ci			memcpy(&buf[offset], &remainder, last_len);
71462306a36Sopenharmony_ci		} else {
71562306a36Sopenharmony_ci			memcpy(&remainder, &buf[offset], last_len);
71662306a36Sopenharmony_ci			writel_relaxed(remainder, nfc->base + DATA_PORT_REG);
71762306a36Sopenharmony_ci		}
71862306a36Sopenharmony_ci	}
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci	return anfc_wait_for_event(nfc, XFER_COMPLETE);
72162306a36Sopenharmony_ci}
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_cistatic int anfc_misc_data_type_exec(struct nand_chip *chip,
72462306a36Sopenharmony_ci				    const struct nand_subop *subop,
72562306a36Sopenharmony_ci				    u32 prog_reg)
72662306a36Sopenharmony_ci{
72762306a36Sopenharmony_ci	struct arasan_nfc *nfc = to_anfc(chip->controller);
72862306a36Sopenharmony_ci	struct anfc_op nfc_op = {};
72962306a36Sopenharmony_ci	int ret;
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci	ret = anfc_parse_instructions(chip, subop, &nfc_op);
73262306a36Sopenharmony_ci	if (ret)
73362306a36Sopenharmony_ci		return ret;
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci	nfc_op.prog_reg = prog_reg;
73662306a36Sopenharmony_ci	anfc_trigger_op(nfc, &nfc_op);
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ci	if (nfc_op.rdy_timeout_ms) {
73962306a36Sopenharmony_ci		ret = anfc_wait_for_rb(nfc, chip, nfc_op.rdy_timeout_ms);
74062306a36Sopenharmony_ci		if (ret)
74162306a36Sopenharmony_ci			return ret;
74262306a36Sopenharmony_ci	}
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_ci	return anfc_rw_pio_op(nfc, &nfc_op);
74562306a36Sopenharmony_ci}
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_cistatic int anfc_param_read_type_exec(struct nand_chip *chip,
74862306a36Sopenharmony_ci				     const struct nand_subop *subop)
74962306a36Sopenharmony_ci{
75062306a36Sopenharmony_ci	return anfc_misc_data_type_exec(chip, subop, PROG_RDPARAM);
75162306a36Sopenharmony_ci}
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_cistatic int anfc_data_read_type_exec(struct nand_chip *chip,
75462306a36Sopenharmony_ci				    const struct nand_subop *subop)
75562306a36Sopenharmony_ci{
75662306a36Sopenharmony_ci	u32 prog_reg = PROG_PGRD;
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_ci	/*
75962306a36Sopenharmony_ci	 * Experience shows that while in SDR mode sending a CHANGE READ COLUMN
76062306a36Sopenharmony_ci	 * command through the READ PAGE "type" always works fine, when in
76162306a36Sopenharmony_ci	 * NV-DDR mode the same command simply fails. However, it was also
76262306a36Sopenharmony_ci	 * spotted that any CHANGE READ COLUMN command sent through the CHANGE
76362306a36Sopenharmony_ci	 * READ COLUMN ENHANCED "type" would correctly work in both cases (SDR
76462306a36Sopenharmony_ci	 * and NV-DDR). So, for simplicity, let's program the controller with
76562306a36Sopenharmony_ci	 * the CHANGE READ COLUMN ENHANCED "type" whenever we are requested to
76662306a36Sopenharmony_ci	 * perform a CHANGE READ COLUMN operation.
76762306a36Sopenharmony_ci	 */
76862306a36Sopenharmony_ci	if (subop->instrs[0].ctx.cmd.opcode == NAND_CMD_RNDOUT &&
76962306a36Sopenharmony_ci	    subop->instrs[2].ctx.cmd.opcode == NAND_CMD_RNDOUTSTART)
77062306a36Sopenharmony_ci		prog_reg = PROG_CHG_RD_COL_ENH;
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci	return anfc_misc_data_type_exec(chip, subop, prog_reg);
77362306a36Sopenharmony_ci}
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_cistatic int anfc_param_write_type_exec(struct nand_chip *chip,
77662306a36Sopenharmony_ci				      const struct nand_subop *subop)
77762306a36Sopenharmony_ci{
77862306a36Sopenharmony_ci	return anfc_misc_data_type_exec(chip, subop, PROG_SET_FEATURE);
77962306a36Sopenharmony_ci}
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_cistatic int anfc_data_write_type_exec(struct nand_chip *chip,
78262306a36Sopenharmony_ci				     const struct nand_subop *subop)
78362306a36Sopenharmony_ci{
78462306a36Sopenharmony_ci	return anfc_misc_data_type_exec(chip, subop, PROG_PGPROG);
78562306a36Sopenharmony_ci}
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_cistatic int anfc_misc_zerolen_type_exec(struct nand_chip *chip,
78862306a36Sopenharmony_ci				       const struct nand_subop *subop,
78962306a36Sopenharmony_ci				       u32 prog_reg)
79062306a36Sopenharmony_ci{
79162306a36Sopenharmony_ci	struct arasan_nfc *nfc = to_anfc(chip->controller);
79262306a36Sopenharmony_ci	struct anfc_op nfc_op = {};
79362306a36Sopenharmony_ci	int ret;
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci	ret = anfc_parse_instructions(chip, subop, &nfc_op);
79662306a36Sopenharmony_ci	if (ret)
79762306a36Sopenharmony_ci		return ret;
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci	nfc_op.prog_reg = prog_reg;
80062306a36Sopenharmony_ci	anfc_trigger_op(nfc, &nfc_op);
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_ci	ret = anfc_wait_for_event(nfc, XFER_COMPLETE);
80362306a36Sopenharmony_ci	if (ret)
80462306a36Sopenharmony_ci		return ret;
80562306a36Sopenharmony_ci
80662306a36Sopenharmony_ci	if (nfc_op.rdy_timeout_ms)
80762306a36Sopenharmony_ci		ret = anfc_wait_for_rb(nfc, chip, nfc_op.rdy_timeout_ms);
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci	return ret;
81062306a36Sopenharmony_ci}
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_cistatic int anfc_status_type_exec(struct nand_chip *chip,
81362306a36Sopenharmony_ci				 const struct nand_subop *subop)
81462306a36Sopenharmony_ci{
81562306a36Sopenharmony_ci	struct arasan_nfc *nfc = to_anfc(chip->controller);
81662306a36Sopenharmony_ci	u32 tmp;
81762306a36Sopenharmony_ci	int ret;
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_ci	/* See anfc_check_op() for details about this constraint */
82062306a36Sopenharmony_ci	if (subop->instrs[0].ctx.cmd.opcode != NAND_CMD_STATUS)
82162306a36Sopenharmony_ci		return -ENOTSUPP;
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ci	ret = anfc_misc_zerolen_type_exec(chip, subop, PROG_STATUS);
82462306a36Sopenharmony_ci	if (ret)
82562306a36Sopenharmony_ci		return ret;
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci	tmp = readl_relaxed(nfc->base + FLASH_STS_REG);
82862306a36Sopenharmony_ci	memcpy(subop->instrs[1].ctx.data.buf.in, &tmp, 1);
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_ci	return 0;
83162306a36Sopenharmony_ci}
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_cistatic int anfc_reset_type_exec(struct nand_chip *chip,
83462306a36Sopenharmony_ci				const struct nand_subop *subop)
83562306a36Sopenharmony_ci{
83662306a36Sopenharmony_ci	return anfc_misc_zerolen_type_exec(chip, subop, PROG_RST);
83762306a36Sopenharmony_ci}
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_cistatic int anfc_erase_type_exec(struct nand_chip *chip,
84062306a36Sopenharmony_ci				const struct nand_subop *subop)
84162306a36Sopenharmony_ci{
84262306a36Sopenharmony_ci	return anfc_misc_zerolen_type_exec(chip, subop, PROG_ERASE);
84362306a36Sopenharmony_ci}
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_cistatic int anfc_wait_type_exec(struct nand_chip *chip,
84662306a36Sopenharmony_ci			       const struct nand_subop *subop)
84762306a36Sopenharmony_ci{
84862306a36Sopenharmony_ci	struct arasan_nfc *nfc = to_anfc(chip->controller);
84962306a36Sopenharmony_ci	struct anfc_op nfc_op = {};
85062306a36Sopenharmony_ci	int ret;
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_ci	ret = anfc_parse_instructions(chip, subop, &nfc_op);
85362306a36Sopenharmony_ci	if (ret)
85462306a36Sopenharmony_ci		return ret;
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_ci	return anfc_wait_for_rb(nfc, chip, nfc_op.rdy_timeout_ms);
85762306a36Sopenharmony_ci}
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_cistatic const struct nand_op_parser anfc_op_parser = NAND_OP_PARSER(
86062306a36Sopenharmony_ci	NAND_OP_PARSER_PATTERN(
86162306a36Sopenharmony_ci		anfc_param_read_type_exec,
86262306a36Sopenharmony_ci		NAND_OP_PARSER_PAT_CMD_ELEM(false),
86362306a36Sopenharmony_ci		NAND_OP_PARSER_PAT_ADDR_ELEM(false, ANFC_MAX_ADDR_CYC),
86462306a36Sopenharmony_ci		NAND_OP_PARSER_PAT_WAITRDY_ELEM(true),
86562306a36Sopenharmony_ci		NAND_OP_PARSER_PAT_DATA_IN_ELEM(false, ANFC_MAX_CHUNK_SIZE)),
86662306a36Sopenharmony_ci	NAND_OP_PARSER_PATTERN(
86762306a36Sopenharmony_ci		anfc_param_write_type_exec,
86862306a36Sopenharmony_ci		NAND_OP_PARSER_PAT_CMD_ELEM(false),
86962306a36Sopenharmony_ci		NAND_OP_PARSER_PAT_ADDR_ELEM(false, ANFC_MAX_ADDR_CYC),
87062306a36Sopenharmony_ci		NAND_OP_PARSER_PAT_DATA_OUT_ELEM(false, ANFC_MAX_PARAM_SIZE)),
87162306a36Sopenharmony_ci	NAND_OP_PARSER_PATTERN(
87262306a36Sopenharmony_ci		anfc_data_read_type_exec,
87362306a36Sopenharmony_ci		NAND_OP_PARSER_PAT_CMD_ELEM(false),
87462306a36Sopenharmony_ci		NAND_OP_PARSER_PAT_ADDR_ELEM(false, ANFC_MAX_ADDR_CYC),
87562306a36Sopenharmony_ci		NAND_OP_PARSER_PAT_CMD_ELEM(false),
87662306a36Sopenharmony_ci		NAND_OP_PARSER_PAT_WAITRDY_ELEM(true),
87762306a36Sopenharmony_ci		NAND_OP_PARSER_PAT_DATA_IN_ELEM(true, ANFC_MAX_CHUNK_SIZE)),
87862306a36Sopenharmony_ci	NAND_OP_PARSER_PATTERN(
87962306a36Sopenharmony_ci		anfc_data_write_type_exec,
88062306a36Sopenharmony_ci		NAND_OP_PARSER_PAT_CMD_ELEM(false),
88162306a36Sopenharmony_ci		NAND_OP_PARSER_PAT_ADDR_ELEM(false, ANFC_MAX_ADDR_CYC),
88262306a36Sopenharmony_ci		NAND_OP_PARSER_PAT_DATA_OUT_ELEM(false, ANFC_MAX_CHUNK_SIZE),
88362306a36Sopenharmony_ci		NAND_OP_PARSER_PAT_CMD_ELEM(false)),
88462306a36Sopenharmony_ci	NAND_OP_PARSER_PATTERN(
88562306a36Sopenharmony_ci		anfc_reset_type_exec,
88662306a36Sopenharmony_ci		NAND_OP_PARSER_PAT_CMD_ELEM(false),
88762306a36Sopenharmony_ci		NAND_OP_PARSER_PAT_WAITRDY_ELEM(false)),
88862306a36Sopenharmony_ci	NAND_OP_PARSER_PATTERN(
88962306a36Sopenharmony_ci		anfc_erase_type_exec,
89062306a36Sopenharmony_ci		NAND_OP_PARSER_PAT_CMD_ELEM(false),
89162306a36Sopenharmony_ci		NAND_OP_PARSER_PAT_ADDR_ELEM(false, ANFC_MAX_ADDR_CYC),
89262306a36Sopenharmony_ci		NAND_OP_PARSER_PAT_CMD_ELEM(false),
89362306a36Sopenharmony_ci		NAND_OP_PARSER_PAT_WAITRDY_ELEM(false)),
89462306a36Sopenharmony_ci	NAND_OP_PARSER_PATTERN(
89562306a36Sopenharmony_ci		anfc_status_type_exec,
89662306a36Sopenharmony_ci		NAND_OP_PARSER_PAT_CMD_ELEM(false),
89762306a36Sopenharmony_ci		NAND_OP_PARSER_PAT_DATA_IN_ELEM(false, ANFC_MAX_CHUNK_SIZE)),
89862306a36Sopenharmony_ci	NAND_OP_PARSER_PATTERN(
89962306a36Sopenharmony_ci		anfc_wait_type_exec,
90062306a36Sopenharmony_ci		NAND_OP_PARSER_PAT_WAITRDY_ELEM(false)),
90162306a36Sopenharmony_ci	);
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_cistatic int anfc_check_op(struct nand_chip *chip,
90462306a36Sopenharmony_ci			 const struct nand_operation *op)
90562306a36Sopenharmony_ci{
90662306a36Sopenharmony_ci	const struct nand_op_instr *instr;
90762306a36Sopenharmony_ci	int op_id;
90862306a36Sopenharmony_ci
90962306a36Sopenharmony_ci	/*
91062306a36Sopenharmony_ci	 * The controller abstracts all the NAND operations and do not support
91162306a36Sopenharmony_ci	 * data only operations.
91262306a36Sopenharmony_ci	 *
91362306a36Sopenharmony_ci	 * TODO: The nand_op_parser framework should be extended to
91462306a36Sopenharmony_ci	 * support custom checks on DATA instructions.
91562306a36Sopenharmony_ci	 */
91662306a36Sopenharmony_ci	for (op_id = 0; op_id < op->ninstrs; op_id++) {
91762306a36Sopenharmony_ci		instr = &op->instrs[op_id];
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci		switch (instr->type) {
92062306a36Sopenharmony_ci		case NAND_OP_ADDR_INSTR:
92162306a36Sopenharmony_ci			if (instr->ctx.addr.naddrs > ANFC_MAX_ADDR_CYC)
92262306a36Sopenharmony_ci				return -ENOTSUPP;
92362306a36Sopenharmony_ci
92462306a36Sopenharmony_ci			break;
92562306a36Sopenharmony_ci		case NAND_OP_DATA_IN_INSTR:
92662306a36Sopenharmony_ci		case NAND_OP_DATA_OUT_INSTR:
92762306a36Sopenharmony_ci			if (instr->ctx.data.len > ANFC_MAX_CHUNK_SIZE)
92862306a36Sopenharmony_ci				return -ENOTSUPP;
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_ci			if (anfc_pkt_len_config(instr->ctx.data.len, NULL, NULL))
93162306a36Sopenharmony_ci				return -ENOTSUPP;
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_ci			break;
93462306a36Sopenharmony_ci		default:
93562306a36Sopenharmony_ci			break;
93662306a36Sopenharmony_ci		}
93762306a36Sopenharmony_ci	}
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ci	/*
94062306a36Sopenharmony_ci	 * The controller does not allow to proceed with a CMD+DATA_IN cycle
94162306a36Sopenharmony_ci	 * manually on the bus by reading data from the data register. Instead,
94262306a36Sopenharmony_ci	 * the controller abstract a status read operation with its own status
94362306a36Sopenharmony_ci	 * register after ordering a read status operation. Hence, we cannot
94462306a36Sopenharmony_ci	 * support any CMD+DATA_IN operation other than a READ STATUS.
94562306a36Sopenharmony_ci	 *
94662306a36Sopenharmony_ci	 * TODO: The nand_op_parser() framework should be extended to describe
94762306a36Sopenharmony_ci	 * fixed patterns instead of open-coding this check here.
94862306a36Sopenharmony_ci	 */
94962306a36Sopenharmony_ci	if (op->ninstrs == 2 &&
95062306a36Sopenharmony_ci	    op->instrs[0].type == NAND_OP_CMD_INSTR &&
95162306a36Sopenharmony_ci	    op->instrs[0].ctx.cmd.opcode != NAND_CMD_STATUS &&
95262306a36Sopenharmony_ci	    op->instrs[1].type == NAND_OP_DATA_IN_INSTR)
95362306a36Sopenharmony_ci		return -ENOTSUPP;
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_ci	return nand_op_parser_exec_op(chip, &anfc_op_parser, op, true);
95662306a36Sopenharmony_ci}
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_cistatic int anfc_exec_op(struct nand_chip *chip,
95962306a36Sopenharmony_ci			const struct nand_operation *op,
96062306a36Sopenharmony_ci			bool check_only)
96162306a36Sopenharmony_ci{
96262306a36Sopenharmony_ci	int ret;
96362306a36Sopenharmony_ci
96462306a36Sopenharmony_ci	if (check_only)
96562306a36Sopenharmony_ci		return anfc_check_op(chip, op);
96662306a36Sopenharmony_ci
96762306a36Sopenharmony_ci	ret = anfc_select_target(chip, op->cs);
96862306a36Sopenharmony_ci	if (ret)
96962306a36Sopenharmony_ci		return ret;
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ci	return nand_op_parser_exec_op(chip, &anfc_op_parser, op, check_only);
97262306a36Sopenharmony_ci}
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_cistatic int anfc_setup_interface(struct nand_chip *chip, int target,
97562306a36Sopenharmony_ci				const struct nand_interface_config *conf)
97662306a36Sopenharmony_ci{
97762306a36Sopenharmony_ci	struct anand *anand = to_anand(chip);
97862306a36Sopenharmony_ci	struct arasan_nfc *nfc = to_anfc(chip->controller);
97962306a36Sopenharmony_ci	struct device_node *np = nfc->dev->of_node;
98062306a36Sopenharmony_ci	const struct nand_sdr_timings *sdr;
98162306a36Sopenharmony_ci	const struct nand_nvddr_timings *nvddr;
98262306a36Sopenharmony_ci	unsigned int tccs_min, dqs_mode, fast_tcad;
98362306a36Sopenharmony_ci
98462306a36Sopenharmony_ci	if (nand_interface_is_nvddr(conf)) {
98562306a36Sopenharmony_ci		nvddr = nand_get_nvddr_timings(conf);
98662306a36Sopenharmony_ci		if (IS_ERR(nvddr))
98762306a36Sopenharmony_ci			return PTR_ERR(nvddr);
98862306a36Sopenharmony_ci	} else {
98962306a36Sopenharmony_ci		sdr = nand_get_sdr_timings(conf);
99062306a36Sopenharmony_ci		if (IS_ERR(sdr))
99162306a36Sopenharmony_ci			return PTR_ERR(sdr);
99262306a36Sopenharmony_ci	}
99362306a36Sopenharmony_ci
99462306a36Sopenharmony_ci	if (target < 0)
99562306a36Sopenharmony_ci		return 0;
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_ci	if (nand_interface_is_sdr(conf)) {
99862306a36Sopenharmony_ci		anand->data_iface = DIFACE_SDR |
99962306a36Sopenharmony_ci				    DIFACE_SDR_MODE(conf->timings.mode);
100062306a36Sopenharmony_ci		anand->timings = 0;
100162306a36Sopenharmony_ci	} else {
100262306a36Sopenharmony_ci		anand->data_iface = DIFACE_NVDDR |
100362306a36Sopenharmony_ci				    DIFACE_DDR_MODE(conf->timings.mode);
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_ci		if (conf->timings.nvddr.tCCS_min <= 100000)
100662306a36Sopenharmony_ci			tccs_min = TCCS_TIME_100NS;
100762306a36Sopenharmony_ci		else if (conf->timings.nvddr.tCCS_min <= 200000)
100862306a36Sopenharmony_ci			tccs_min = TCCS_TIME_200NS;
100962306a36Sopenharmony_ci		else if (conf->timings.nvddr.tCCS_min <= 300000)
101062306a36Sopenharmony_ci			tccs_min = TCCS_TIME_300NS;
101162306a36Sopenharmony_ci		else
101262306a36Sopenharmony_ci			tccs_min = TCCS_TIME_500NS;
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_ci		fast_tcad = 0;
101562306a36Sopenharmony_ci		if (conf->timings.nvddr.tCAD_min < 45000)
101662306a36Sopenharmony_ci			fast_tcad = FAST_TCAD;
101762306a36Sopenharmony_ci
101862306a36Sopenharmony_ci		switch (conf->timings.mode) {
101962306a36Sopenharmony_ci		case 5:
102062306a36Sopenharmony_ci		case 4:
102162306a36Sopenharmony_ci			dqs_mode = 2;
102262306a36Sopenharmony_ci			break;
102362306a36Sopenharmony_ci		case 3:
102462306a36Sopenharmony_ci			dqs_mode = 3;
102562306a36Sopenharmony_ci			break;
102662306a36Sopenharmony_ci		case 2:
102762306a36Sopenharmony_ci			dqs_mode = 4;
102862306a36Sopenharmony_ci			break;
102962306a36Sopenharmony_ci		case 1:
103062306a36Sopenharmony_ci			dqs_mode = 5;
103162306a36Sopenharmony_ci			break;
103262306a36Sopenharmony_ci		case 0:
103362306a36Sopenharmony_ci		default:
103462306a36Sopenharmony_ci			dqs_mode = 6;
103562306a36Sopenharmony_ci			break;
103662306a36Sopenharmony_ci		}
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_ci		anand->timings = tccs_min | fast_tcad |
103962306a36Sopenharmony_ci				 DQS_BUFF_SEL_IN(dqs_mode) |
104062306a36Sopenharmony_ci				 DQS_BUFF_SEL_OUT(dqs_mode);
104162306a36Sopenharmony_ci	}
104262306a36Sopenharmony_ci
104362306a36Sopenharmony_ci	if (nand_interface_is_sdr(conf)) {
104462306a36Sopenharmony_ci		anand->clk = ANFC_XLNX_SDR_DFLT_CORE_CLK;
104562306a36Sopenharmony_ci	} else {
104662306a36Sopenharmony_ci		/* ONFI timings are defined in picoseconds */
104762306a36Sopenharmony_ci		anand->clk = div_u64((u64)NSEC_PER_SEC * 1000,
104862306a36Sopenharmony_ci				     conf->timings.nvddr.tCK_min);
104962306a36Sopenharmony_ci	}
105062306a36Sopenharmony_ci
105162306a36Sopenharmony_ci	/*
105262306a36Sopenharmony_ci	 * Due to a hardware bug in the ZynqMP SoC, SDR timing modes 0-1 work
105362306a36Sopenharmony_ci	 * with f > 90MHz (default clock is 100MHz) but signals are unstable
105462306a36Sopenharmony_ci	 * with higher modes. Hence we decrease a little bit the clock rate to
105562306a36Sopenharmony_ci	 * 80MHz when using SDR modes 2-5 with this SoC.
105662306a36Sopenharmony_ci	 */
105762306a36Sopenharmony_ci	if (of_device_is_compatible(np, "xlnx,zynqmp-nand-controller") &&
105862306a36Sopenharmony_ci	    nand_interface_is_sdr(conf) && conf->timings.mode >= 2)
105962306a36Sopenharmony_ci		anand->clk = ANFC_XLNX_SDR_HS_CORE_CLK;
106062306a36Sopenharmony_ci
106162306a36Sopenharmony_ci	return 0;
106262306a36Sopenharmony_ci}
106362306a36Sopenharmony_ci
106462306a36Sopenharmony_cistatic int anfc_calc_hw_ecc_bytes(int step_size, int strength)
106562306a36Sopenharmony_ci{
106662306a36Sopenharmony_ci	unsigned int bch_gf_mag, ecc_bits;
106762306a36Sopenharmony_ci
106862306a36Sopenharmony_ci	switch (step_size) {
106962306a36Sopenharmony_ci	case SZ_512:
107062306a36Sopenharmony_ci		bch_gf_mag = 13;
107162306a36Sopenharmony_ci		break;
107262306a36Sopenharmony_ci	case SZ_1K:
107362306a36Sopenharmony_ci		bch_gf_mag = 14;
107462306a36Sopenharmony_ci		break;
107562306a36Sopenharmony_ci	default:
107662306a36Sopenharmony_ci		return -EINVAL;
107762306a36Sopenharmony_ci	}
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_ci	ecc_bits = bch_gf_mag * strength;
108062306a36Sopenharmony_ci
108162306a36Sopenharmony_ci	return DIV_ROUND_UP(ecc_bits, 8);
108262306a36Sopenharmony_ci}
108362306a36Sopenharmony_ci
108462306a36Sopenharmony_cistatic const int anfc_hw_ecc_512_strengths[] = {4, 8, 12};
108562306a36Sopenharmony_ci
108662306a36Sopenharmony_cistatic const int anfc_hw_ecc_1024_strengths[] = {24};
108762306a36Sopenharmony_ci
108862306a36Sopenharmony_cistatic const struct nand_ecc_step_info anfc_hw_ecc_step_infos[] = {
108962306a36Sopenharmony_ci	{
109062306a36Sopenharmony_ci		.stepsize = SZ_512,
109162306a36Sopenharmony_ci		.strengths = anfc_hw_ecc_512_strengths,
109262306a36Sopenharmony_ci		.nstrengths = ARRAY_SIZE(anfc_hw_ecc_512_strengths),
109362306a36Sopenharmony_ci	},
109462306a36Sopenharmony_ci	{
109562306a36Sopenharmony_ci		.stepsize = SZ_1K,
109662306a36Sopenharmony_ci		.strengths = anfc_hw_ecc_1024_strengths,
109762306a36Sopenharmony_ci		.nstrengths = ARRAY_SIZE(anfc_hw_ecc_1024_strengths),
109862306a36Sopenharmony_ci	},
109962306a36Sopenharmony_ci};
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_cistatic const struct nand_ecc_caps anfc_hw_ecc_caps = {
110262306a36Sopenharmony_ci	.stepinfos = anfc_hw_ecc_step_infos,
110362306a36Sopenharmony_ci	.nstepinfos = ARRAY_SIZE(anfc_hw_ecc_step_infos),
110462306a36Sopenharmony_ci	.calc_ecc_bytes = anfc_calc_hw_ecc_bytes,
110562306a36Sopenharmony_ci};
110662306a36Sopenharmony_ci
110762306a36Sopenharmony_cistatic int anfc_init_hw_ecc_controller(struct arasan_nfc *nfc,
110862306a36Sopenharmony_ci				       struct nand_chip *chip)
110962306a36Sopenharmony_ci{
111062306a36Sopenharmony_ci	struct anand *anand = to_anand(chip);
111162306a36Sopenharmony_ci	struct mtd_info *mtd = nand_to_mtd(chip);
111262306a36Sopenharmony_ci	struct nand_ecc_ctrl *ecc = &chip->ecc;
111362306a36Sopenharmony_ci	unsigned int bch_prim_poly = 0, bch_gf_mag = 0, ecc_offset;
111462306a36Sopenharmony_ci	int ret;
111562306a36Sopenharmony_ci
111662306a36Sopenharmony_ci	switch (mtd->writesize) {
111762306a36Sopenharmony_ci	case SZ_512:
111862306a36Sopenharmony_ci	case SZ_2K:
111962306a36Sopenharmony_ci	case SZ_4K:
112062306a36Sopenharmony_ci	case SZ_8K:
112162306a36Sopenharmony_ci	case SZ_16K:
112262306a36Sopenharmony_ci		break;
112362306a36Sopenharmony_ci	default:
112462306a36Sopenharmony_ci		dev_err(nfc->dev, "Unsupported page size %d\n", mtd->writesize);
112562306a36Sopenharmony_ci		return -EINVAL;
112662306a36Sopenharmony_ci	}
112762306a36Sopenharmony_ci
112862306a36Sopenharmony_ci	ret = nand_ecc_choose_conf(chip, &anfc_hw_ecc_caps, mtd->oobsize);
112962306a36Sopenharmony_ci	if (ret)
113062306a36Sopenharmony_ci		return ret;
113162306a36Sopenharmony_ci
113262306a36Sopenharmony_ci	switch (ecc->strength) {
113362306a36Sopenharmony_ci	case 12:
113462306a36Sopenharmony_ci		anand->strength = 0x1;
113562306a36Sopenharmony_ci		break;
113662306a36Sopenharmony_ci	case 8:
113762306a36Sopenharmony_ci		anand->strength = 0x2;
113862306a36Sopenharmony_ci		break;
113962306a36Sopenharmony_ci	case 4:
114062306a36Sopenharmony_ci		anand->strength = 0x3;
114162306a36Sopenharmony_ci		break;
114262306a36Sopenharmony_ci	case 24:
114362306a36Sopenharmony_ci		anand->strength = 0x4;
114462306a36Sopenharmony_ci		break;
114562306a36Sopenharmony_ci	default:
114662306a36Sopenharmony_ci		dev_err(nfc->dev, "Unsupported strength %d\n", ecc->strength);
114762306a36Sopenharmony_ci		return -EINVAL;
114862306a36Sopenharmony_ci	}
114962306a36Sopenharmony_ci
115062306a36Sopenharmony_ci	switch (ecc->size) {
115162306a36Sopenharmony_ci	case SZ_512:
115262306a36Sopenharmony_ci		bch_gf_mag = 13;
115362306a36Sopenharmony_ci		bch_prim_poly = 0x201b;
115462306a36Sopenharmony_ci		break;
115562306a36Sopenharmony_ci	case SZ_1K:
115662306a36Sopenharmony_ci		bch_gf_mag = 14;
115762306a36Sopenharmony_ci		bch_prim_poly = 0x4443;
115862306a36Sopenharmony_ci		break;
115962306a36Sopenharmony_ci	default:
116062306a36Sopenharmony_ci		dev_err(nfc->dev, "Unsupported step size %d\n", ecc->strength);
116162306a36Sopenharmony_ci		return -EINVAL;
116262306a36Sopenharmony_ci	}
116362306a36Sopenharmony_ci
116462306a36Sopenharmony_ci	mtd_set_ooblayout(mtd, nand_get_large_page_ooblayout());
116562306a36Sopenharmony_ci
116662306a36Sopenharmony_ci	ecc->steps = mtd->writesize / ecc->size;
116762306a36Sopenharmony_ci	ecc->algo = NAND_ECC_ALGO_BCH;
116862306a36Sopenharmony_ci	anand->ecc_bits = bch_gf_mag * ecc->strength;
116962306a36Sopenharmony_ci	ecc->bytes = DIV_ROUND_UP(anand->ecc_bits, 8);
117062306a36Sopenharmony_ci	anand->ecc_total = DIV_ROUND_UP(anand->ecc_bits * ecc->steps, 8);
117162306a36Sopenharmony_ci	ecc_offset = mtd->writesize + mtd->oobsize - anand->ecc_total;
117262306a36Sopenharmony_ci	anand->ecc_conf = ECC_CONF_COL(ecc_offset) |
117362306a36Sopenharmony_ci			  ECC_CONF_LEN(anand->ecc_total) |
117462306a36Sopenharmony_ci			  ECC_CONF_BCH_EN;
117562306a36Sopenharmony_ci
117662306a36Sopenharmony_ci	anand->errloc = devm_kmalloc_array(nfc->dev, ecc->strength,
117762306a36Sopenharmony_ci					   sizeof(*anand->errloc), GFP_KERNEL);
117862306a36Sopenharmony_ci	if (!anand->errloc)
117962306a36Sopenharmony_ci		return -ENOMEM;
118062306a36Sopenharmony_ci
118162306a36Sopenharmony_ci	anand->hw_ecc = devm_kmalloc(nfc->dev, ecc->bytes, GFP_KERNEL);
118262306a36Sopenharmony_ci	if (!anand->hw_ecc)
118362306a36Sopenharmony_ci		return -ENOMEM;
118462306a36Sopenharmony_ci
118562306a36Sopenharmony_ci	/* Enforce bit swapping to fit the hardware */
118662306a36Sopenharmony_ci	anand->bch = bch_init(bch_gf_mag, ecc->strength, bch_prim_poly, true);
118762306a36Sopenharmony_ci	if (!anand->bch)
118862306a36Sopenharmony_ci		return -EINVAL;
118962306a36Sopenharmony_ci
119062306a36Sopenharmony_ci	ecc->read_page = anfc_sel_read_page_hw_ecc;
119162306a36Sopenharmony_ci	ecc->write_page = anfc_sel_write_page_hw_ecc;
119262306a36Sopenharmony_ci
119362306a36Sopenharmony_ci	return 0;
119462306a36Sopenharmony_ci}
119562306a36Sopenharmony_ci
119662306a36Sopenharmony_cistatic int anfc_attach_chip(struct nand_chip *chip)
119762306a36Sopenharmony_ci{
119862306a36Sopenharmony_ci	struct anand *anand = to_anand(chip);
119962306a36Sopenharmony_ci	struct arasan_nfc *nfc = to_anfc(chip->controller);
120062306a36Sopenharmony_ci	struct mtd_info *mtd = nand_to_mtd(chip);
120162306a36Sopenharmony_ci	int ret = 0;
120262306a36Sopenharmony_ci
120362306a36Sopenharmony_ci	if (mtd->writesize <= SZ_512)
120462306a36Sopenharmony_ci		anand->caddr_cycles = 1;
120562306a36Sopenharmony_ci	else
120662306a36Sopenharmony_ci		anand->caddr_cycles = 2;
120762306a36Sopenharmony_ci
120862306a36Sopenharmony_ci	if (chip->options & NAND_ROW_ADDR_3)
120962306a36Sopenharmony_ci		anand->raddr_cycles = 3;
121062306a36Sopenharmony_ci	else
121162306a36Sopenharmony_ci		anand->raddr_cycles = 2;
121262306a36Sopenharmony_ci
121362306a36Sopenharmony_ci	switch (mtd->writesize) {
121462306a36Sopenharmony_ci	case 512:
121562306a36Sopenharmony_ci		anand->page_sz = 0;
121662306a36Sopenharmony_ci		break;
121762306a36Sopenharmony_ci	case 1024:
121862306a36Sopenharmony_ci		anand->page_sz = 5;
121962306a36Sopenharmony_ci		break;
122062306a36Sopenharmony_ci	case 2048:
122162306a36Sopenharmony_ci		anand->page_sz = 1;
122262306a36Sopenharmony_ci		break;
122362306a36Sopenharmony_ci	case 4096:
122462306a36Sopenharmony_ci		anand->page_sz = 2;
122562306a36Sopenharmony_ci		break;
122662306a36Sopenharmony_ci	case 8192:
122762306a36Sopenharmony_ci		anand->page_sz = 3;
122862306a36Sopenharmony_ci		break;
122962306a36Sopenharmony_ci	case 16384:
123062306a36Sopenharmony_ci		anand->page_sz = 4;
123162306a36Sopenharmony_ci		break;
123262306a36Sopenharmony_ci	default:
123362306a36Sopenharmony_ci		return -EINVAL;
123462306a36Sopenharmony_ci	}
123562306a36Sopenharmony_ci
123662306a36Sopenharmony_ci	/* These hooks are valid for all ECC providers */
123762306a36Sopenharmony_ci	chip->ecc.read_page_raw = nand_monolithic_read_page_raw;
123862306a36Sopenharmony_ci	chip->ecc.write_page_raw = nand_monolithic_write_page_raw;
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_ci	switch (chip->ecc.engine_type) {
124162306a36Sopenharmony_ci	case NAND_ECC_ENGINE_TYPE_NONE:
124262306a36Sopenharmony_ci	case NAND_ECC_ENGINE_TYPE_SOFT:
124362306a36Sopenharmony_ci	case NAND_ECC_ENGINE_TYPE_ON_DIE:
124462306a36Sopenharmony_ci		break;
124562306a36Sopenharmony_ci	case NAND_ECC_ENGINE_TYPE_ON_HOST:
124662306a36Sopenharmony_ci		ret = anfc_init_hw_ecc_controller(nfc, chip);
124762306a36Sopenharmony_ci		break;
124862306a36Sopenharmony_ci	default:
124962306a36Sopenharmony_ci		dev_err(nfc->dev, "Unsupported ECC mode: %d\n",
125062306a36Sopenharmony_ci			chip->ecc.engine_type);
125162306a36Sopenharmony_ci		return -EINVAL;
125262306a36Sopenharmony_ci	}
125362306a36Sopenharmony_ci
125462306a36Sopenharmony_ci	return ret;
125562306a36Sopenharmony_ci}
125662306a36Sopenharmony_ci
125762306a36Sopenharmony_cistatic void anfc_detach_chip(struct nand_chip *chip)
125862306a36Sopenharmony_ci{
125962306a36Sopenharmony_ci	struct anand *anand = to_anand(chip);
126062306a36Sopenharmony_ci
126162306a36Sopenharmony_ci	if (anand->bch)
126262306a36Sopenharmony_ci		bch_free(anand->bch);
126362306a36Sopenharmony_ci}
126462306a36Sopenharmony_ci
126562306a36Sopenharmony_cistatic const struct nand_controller_ops anfc_ops = {
126662306a36Sopenharmony_ci	.exec_op = anfc_exec_op,
126762306a36Sopenharmony_ci	.setup_interface = anfc_setup_interface,
126862306a36Sopenharmony_ci	.attach_chip = anfc_attach_chip,
126962306a36Sopenharmony_ci	.detach_chip = anfc_detach_chip,
127062306a36Sopenharmony_ci};
127162306a36Sopenharmony_ci
127262306a36Sopenharmony_cistatic int anfc_chip_init(struct arasan_nfc *nfc, struct device_node *np)
127362306a36Sopenharmony_ci{
127462306a36Sopenharmony_ci	struct anand *anand;
127562306a36Sopenharmony_ci	struct nand_chip *chip;
127662306a36Sopenharmony_ci	struct mtd_info *mtd;
127762306a36Sopenharmony_ci	int rb, ret, i;
127862306a36Sopenharmony_ci
127962306a36Sopenharmony_ci	anand = devm_kzalloc(nfc->dev, sizeof(*anand), GFP_KERNEL);
128062306a36Sopenharmony_ci	if (!anand)
128162306a36Sopenharmony_ci		return -ENOMEM;
128262306a36Sopenharmony_ci
128362306a36Sopenharmony_ci	/* Chip-select init */
128462306a36Sopenharmony_ci	anand->ncs_idx = of_property_count_elems_of_size(np, "reg", sizeof(u32));
128562306a36Sopenharmony_ci	if (anand->ncs_idx <= 0 || anand->ncs_idx > nfc->ncs) {
128662306a36Sopenharmony_ci		dev_err(nfc->dev, "Invalid reg property\n");
128762306a36Sopenharmony_ci		return -EINVAL;
128862306a36Sopenharmony_ci	}
128962306a36Sopenharmony_ci
129062306a36Sopenharmony_ci	anand->cs_idx = devm_kcalloc(nfc->dev, anand->ncs_idx,
129162306a36Sopenharmony_ci				     sizeof(*anand->cs_idx), GFP_KERNEL);
129262306a36Sopenharmony_ci	if (!anand->cs_idx)
129362306a36Sopenharmony_ci		return -ENOMEM;
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_ci	for (i = 0; i < anand->ncs_idx; i++) {
129662306a36Sopenharmony_ci		ret = of_property_read_u32_index(np, "reg", i,
129762306a36Sopenharmony_ci						 &anand->cs_idx[i]);
129862306a36Sopenharmony_ci		if (ret) {
129962306a36Sopenharmony_ci			dev_err(nfc->dev, "invalid CS property: %d\n", ret);
130062306a36Sopenharmony_ci			return ret;
130162306a36Sopenharmony_ci		}
130262306a36Sopenharmony_ci	}
130362306a36Sopenharmony_ci
130462306a36Sopenharmony_ci	/* Ready-busy init */
130562306a36Sopenharmony_ci	ret = of_property_read_u32(np, "nand-rb", &rb);
130662306a36Sopenharmony_ci	if (ret)
130762306a36Sopenharmony_ci		return ret;
130862306a36Sopenharmony_ci
130962306a36Sopenharmony_ci	if (rb >= ANFC_MAX_CS) {
131062306a36Sopenharmony_ci		dev_err(nfc->dev, "Wrong RB %d\n", rb);
131162306a36Sopenharmony_ci		return -EINVAL;
131262306a36Sopenharmony_ci	}
131362306a36Sopenharmony_ci
131462306a36Sopenharmony_ci	anand->rb = rb;
131562306a36Sopenharmony_ci
131662306a36Sopenharmony_ci	chip = &anand->chip;
131762306a36Sopenharmony_ci	mtd = nand_to_mtd(chip);
131862306a36Sopenharmony_ci	mtd->dev.parent = nfc->dev;
131962306a36Sopenharmony_ci	chip->controller = &nfc->controller;
132062306a36Sopenharmony_ci	chip->options = NAND_BUSWIDTH_AUTO | NAND_NO_SUBPAGE_WRITE |
132162306a36Sopenharmony_ci			NAND_USES_DMA;
132262306a36Sopenharmony_ci
132362306a36Sopenharmony_ci	nand_set_flash_node(chip, np);
132462306a36Sopenharmony_ci	if (!mtd->name) {
132562306a36Sopenharmony_ci		dev_err(nfc->dev, "NAND label property is mandatory\n");
132662306a36Sopenharmony_ci		return -EINVAL;
132762306a36Sopenharmony_ci	}
132862306a36Sopenharmony_ci
132962306a36Sopenharmony_ci	ret = nand_scan(chip, anand->ncs_idx);
133062306a36Sopenharmony_ci	if (ret) {
133162306a36Sopenharmony_ci		dev_err(nfc->dev, "Scan operation failed\n");
133262306a36Sopenharmony_ci		return ret;
133362306a36Sopenharmony_ci	}
133462306a36Sopenharmony_ci
133562306a36Sopenharmony_ci	ret = mtd_device_register(mtd, NULL, 0);
133662306a36Sopenharmony_ci	if (ret) {
133762306a36Sopenharmony_ci		nand_cleanup(chip);
133862306a36Sopenharmony_ci		return ret;
133962306a36Sopenharmony_ci	}
134062306a36Sopenharmony_ci
134162306a36Sopenharmony_ci	list_add_tail(&anand->node, &nfc->chips);
134262306a36Sopenharmony_ci
134362306a36Sopenharmony_ci	return 0;
134462306a36Sopenharmony_ci}
134562306a36Sopenharmony_ci
134662306a36Sopenharmony_cistatic void anfc_chips_cleanup(struct arasan_nfc *nfc)
134762306a36Sopenharmony_ci{
134862306a36Sopenharmony_ci	struct anand *anand, *tmp;
134962306a36Sopenharmony_ci	struct nand_chip *chip;
135062306a36Sopenharmony_ci	int ret;
135162306a36Sopenharmony_ci
135262306a36Sopenharmony_ci	list_for_each_entry_safe(anand, tmp, &nfc->chips, node) {
135362306a36Sopenharmony_ci		chip = &anand->chip;
135462306a36Sopenharmony_ci		ret = mtd_device_unregister(nand_to_mtd(chip));
135562306a36Sopenharmony_ci		WARN_ON(ret);
135662306a36Sopenharmony_ci		nand_cleanup(chip);
135762306a36Sopenharmony_ci		list_del(&anand->node);
135862306a36Sopenharmony_ci	}
135962306a36Sopenharmony_ci}
136062306a36Sopenharmony_ci
136162306a36Sopenharmony_cistatic int anfc_chips_init(struct arasan_nfc *nfc)
136262306a36Sopenharmony_ci{
136362306a36Sopenharmony_ci	struct device_node *np = nfc->dev->of_node, *nand_np;
136462306a36Sopenharmony_ci	int nchips = of_get_child_count(np);
136562306a36Sopenharmony_ci	int ret;
136662306a36Sopenharmony_ci
136762306a36Sopenharmony_ci	if (!nchips) {
136862306a36Sopenharmony_ci		dev_err(nfc->dev, "Incorrect number of NAND chips (%d)\n",
136962306a36Sopenharmony_ci			nchips);
137062306a36Sopenharmony_ci		return -EINVAL;
137162306a36Sopenharmony_ci	}
137262306a36Sopenharmony_ci
137362306a36Sopenharmony_ci	for_each_child_of_node(np, nand_np) {
137462306a36Sopenharmony_ci		ret = anfc_chip_init(nfc, nand_np);
137562306a36Sopenharmony_ci		if (ret) {
137662306a36Sopenharmony_ci			of_node_put(nand_np);
137762306a36Sopenharmony_ci			anfc_chips_cleanup(nfc);
137862306a36Sopenharmony_ci			break;
137962306a36Sopenharmony_ci		}
138062306a36Sopenharmony_ci	}
138162306a36Sopenharmony_ci
138262306a36Sopenharmony_ci	return ret;
138362306a36Sopenharmony_ci}
138462306a36Sopenharmony_ci
138562306a36Sopenharmony_cistatic void anfc_reset(struct arasan_nfc *nfc)
138662306a36Sopenharmony_ci{
138762306a36Sopenharmony_ci	/* Disable interrupt signals */
138862306a36Sopenharmony_ci	writel_relaxed(0, nfc->base + INTR_SIG_EN_REG);
138962306a36Sopenharmony_ci
139062306a36Sopenharmony_ci	/* Enable interrupt status */
139162306a36Sopenharmony_ci	writel_relaxed(EVENT_MASK, nfc->base + INTR_STS_EN_REG);
139262306a36Sopenharmony_ci
139362306a36Sopenharmony_ci	nfc->cur_cs = -1;
139462306a36Sopenharmony_ci}
139562306a36Sopenharmony_ci
139662306a36Sopenharmony_cistatic int anfc_parse_cs(struct arasan_nfc *nfc)
139762306a36Sopenharmony_ci{
139862306a36Sopenharmony_ci	int ret;
139962306a36Sopenharmony_ci
140062306a36Sopenharmony_ci	/* Check the gpio-cs property */
140162306a36Sopenharmony_ci	ret = rawnand_dt_parse_gpio_cs(nfc->dev, &nfc->cs_array, &nfc->ncs);
140262306a36Sopenharmony_ci	if (ret)
140362306a36Sopenharmony_ci		return ret;
140462306a36Sopenharmony_ci
140562306a36Sopenharmony_ci	/*
140662306a36Sopenharmony_ci	 * The controller native CS cannot be both disabled at the same time.
140762306a36Sopenharmony_ci	 * Hence, only one native CS can be used if GPIO CS are needed, so that
140862306a36Sopenharmony_ci	 * the other is selected when a non-native CS must be asserted (not
140962306a36Sopenharmony_ci	 * wired physically or configured as GPIO instead of NAND CS). In this
141062306a36Sopenharmony_ci	 * case, the "not" chosen CS is assigned to nfc->spare_cs and selected
141162306a36Sopenharmony_ci	 * whenever a GPIO CS must be asserted.
141262306a36Sopenharmony_ci	 */
141362306a36Sopenharmony_ci	if (nfc->cs_array && nfc->ncs > 2) {
141462306a36Sopenharmony_ci		if (!nfc->cs_array[0] && !nfc->cs_array[1]) {
141562306a36Sopenharmony_ci			dev_err(nfc->dev,
141662306a36Sopenharmony_ci				"Assign a single native CS when using GPIOs\n");
141762306a36Sopenharmony_ci			return -EINVAL;
141862306a36Sopenharmony_ci		}
141962306a36Sopenharmony_ci
142062306a36Sopenharmony_ci		if (nfc->cs_array[0])
142162306a36Sopenharmony_ci			nfc->spare_cs = 0;
142262306a36Sopenharmony_ci		else
142362306a36Sopenharmony_ci			nfc->spare_cs = 1;
142462306a36Sopenharmony_ci	}
142562306a36Sopenharmony_ci
142662306a36Sopenharmony_ci	if (!nfc->cs_array) {
142762306a36Sopenharmony_ci		nfc->cs_array = anfc_default_cs_array;
142862306a36Sopenharmony_ci		nfc->ncs = ANFC_MAX_CS;
142962306a36Sopenharmony_ci		return 0;
143062306a36Sopenharmony_ci	}
143162306a36Sopenharmony_ci
143262306a36Sopenharmony_ci	return 0;
143362306a36Sopenharmony_ci}
143462306a36Sopenharmony_ci
143562306a36Sopenharmony_cistatic int anfc_probe(struct platform_device *pdev)
143662306a36Sopenharmony_ci{
143762306a36Sopenharmony_ci	struct arasan_nfc *nfc;
143862306a36Sopenharmony_ci	int ret;
143962306a36Sopenharmony_ci
144062306a36Sopenharmony_ci	nfc = devm_kzalloc(&pdev->dev, sizeof(*nfc), GFP_KERNEL);
144162306a36Sopenharmony_ci	if (!nfc)
144262306a36Sopenharmony_ci		return -ENOMEM;
144362306a36Sopenharmony_ci
144462306a36Sopenharmony_ci	nfc->dev = &pdev->dev;
144562306a36Sopenharmony_ci	nand_controller_init(&nfc->controller);
144662306a36Sopenharmony_ci	nfc->controller.ops = &anfc_ops;
144762306a36Sopenharmony_ci	INIT_LIST_HEAD(&nfc->chips);
144862306a36Sopenharmony_ci
144962306a36Sopenharmony_ci	nfc->base = devm_platform_ioremap_resource(pdev, 0);
145062306a36Sopenharmony_ci	if (IS_ERR(nfc->base))
145162306a36Sopenharmony_ci		return PTR_ERR(nfc->base);
145262306a36Sopenharmony_ci
145362306a36Sopenharmony_ci	anfc_reset(nfc);
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_ci	nfc->controller_clk = devm_clk_get_enabled(&pdev->dev, "controller");
145662306a36Sopenharmony_ci	if (IS_ERR(nfc->controller_clk))
145762306a36Sopenharmony_ci		return PTR_ERR(nfc->controller_clk);
145862306a36Sopenharmony_ci
145962306a36Sopenharmony_ci	nfc->bus_clk = devm_clk_get_enabled(&pdev->dev, "bus");
146062306a36Sopenharmony_ci	if (IS_ERR(nfc->bus_clk))
146162306a36Sopenharmony_ci		return PTR_ERR(nfc->bus_clk);
146262306a36Sopenharmony_ci
146362306a36Sopenharmony_ci	ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(64));
146462306a36Sopenharmony_ci	if (ret)
146562306a36Sopenharmony_ci		return ret;
146662306a36Sopenharmony_ci
146762306a36Sopenharmony_ci	ret = anfc_parse_cs(nfc);
146862306a36Sopenharmony_ci	if (ret)
146962306a36Sopenharmony_ci		return ret;
147062306a36Sopenharmony_ci
147162306a36Sopenharmony_ci	ret = anfc_chips_init(nfc);
147262306a36Sopenharmony_ci	if (ret)
147362306a36Sopenharmony_ci		return ret;
147462306a36Sopenharmony_ci
147562306a36Sopenharmony_ci	platform_set_drvdata(pdev, nfc);
147662306a36Sopenharmony_ci
147762306a36Sopenharmony_ci	return 0;
147862306a36Sopenharmony_ci}
147962306a36Sopenharmony_ci
148062306a36Sopenharmony_cistatic void anfc_remove(struct platform_device *pdev)
148162306a36Sopenharmony_ci{
148262306a36Sopenharmony_ci	struct arasan_nfc *nfc = platform_get_drvdata(pdev);
148362306a36Sopenharmony_ci
148462306a36Sopenharmony_ci	anfc_chips_cleanup(nfc);
148562306a36Sopenharmony_ci}
148662306a36Sopenharmony_ci
148762306a36Sopenharmony_cistatic const struct of_device_id anfc_ids[] = {
148862306a36Sopenharmony_ci	{
148962306a36Sopenharmony_ci		.compatible = "xlnx,zynqmp-nand-controller",
149062306a36Sopenharmony_ci	},
149162306a36Sopenharmony_ci	{
149262306a36Sopenharmony_ci		.compatible = "arasan,nfc-v3p10",
149362306a36Sopenharmony_ci	},
149462306a36Sopenharmony_ci	{}
149562306a36Sopenharmony_ci};
149662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, anfc_ids);
149762306a36Sopenharmony_ci
149862306a36Sopenharmony_cistatic struct platform_driver anfc_driver = {
149962306a36Sopenharmony_ci	.driver = {
150062306a36Sopenharmony_ci		.name = "arasan-nand-controller",
150162306a36Sopenharmony_ci		.of_match_table = anfc_ids,
150262306a36Sopenharmony_ci	},
150362306a36Sopenharmony_ci	.probe = anfc_probe,
150462306a36Sopenharmony_ci	.remove_new = anfc_remove,
150562306a36Sopenharmony_ci};
150662306a36Sopenharmony_cimodule_platform_driver(anfc_driver);
150762306a36Sopenharmony_ci
150862306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
150962306a36Sopenharmony_ciMODULE_AUTHOR("Punnaiah Choudary Kalluri <punnaia@xilinx.com>");
151062306a36Sopenharmony_ciMODULE_AUTHOR("Naga Sureshkumar Relli <nagasure@xilinx.com>");
151162306a36Sopenharmony_ciMODULE_AUTHOR("Miquel Raynal <miquel.raynal@bootlin.com>");
151262306a36Sopenharmony_ciMODULE_DESCRIPTION("Arasan NAND Flash Controller Driver");
1513