162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2019 Macronix International Co., Ltd.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Author:
662306a36Sopenharmony_ci *	Mason Yang <masonccyang@mxic.com.tw>
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/clk.h>
1062306a36Sopenharmony_ci#include <linux/io.h>
1162306a36Sopenharmony_ci#include <linux/iopoll.h>
1262306a36Sopenharmony_ci#include <linux/interrupt.h>
1362306a36Sopenharmony_ci#include <linux/module.h>
1462306a36Sopenharmony_ci#include <linux/mtd/mtd.h>
1562306a36Sopenharmony_ci#include <linux/mtd/nand-ecc-sw-hamming.h>
1662306a36Sopenharmony_ci#include <linux/mtd/rawnand.h>
1762306a36Sopenharmony_ci#include <linux/platform_device.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#include "internals.h"
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#define HC_CFG			0x0
2262306a36Sopenharmony_ci#define HC_CFG_IF_CFG(x)	((x) << 27)
2362306a36Sopenharmony_ci#define HC_CFG_DUAL_SLAVE	BIT(31)
2462306a36Sopenharmony_ci#define HC_CFG_INDIVIDUAL	BIT(30)
2562306a36Sopenharmony_ci#define HC_CFG_NIO(x)		(((x) / 4) << 27)
2662306a36Sopenharmony_ci#define HC_CFG_TYPE(s, t)	((t) << (23 + ((s) * 2)))
2762306a36Sopenharmony_ci#define HC_CFG_TYPE_SPI_NOR	0
2862306a36Sopenharmony_ci#define HC_CFG_TYPE_SPI_NAND	1
2962306a36Sopenharmony_ci#define HC_CFG_TYPE_SPI_RAM	2
3062306a36Sopenharmony_ci#define HC_CFG_TYPE_RAW_NAND	3
3162306a36Sopenharmony_ci#define HC_CFG_SLV_ACT(x)	((x) << 21)
3262306a36Sopenharmony_ci#define HC_CFG_CLK_PH_EN	BIT(20)
3362306a36Sopenharmony_ci#define HC_CFG_CLK_POL_INV	BIT(19)
3462306a36Sopenharmony_ci#define HC_CFG_BIG_ENDIAN	BIT(18)
3562306a36Sopenharmony_ci#define HC_CFG_DATA_PASS	BIT(17)
3662306a36Sopenharmony_ci#define HC_CFG_IDLE_SIO_LVL(x)	((x) << 16)
3762306a36Sopenharmony_ci#define HC_CFG_MAN_START_EN	BIT(3)
3862306a36Sopenharmony_ci#define HC_CFG_MAN_START	BIT(2)
3962306a36Sopenharmony_ci#define HC_CFG_MAN_CS_EN	BIT(1)
4062306a36Sopenharmony_ci#define HC_CFG_MAN_CS_ASSERT	BIT(0)
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci#define INT_STS			0x4
4362306a36Sopenharmony_ci#define INT_STS_EN		0x8
4462306a36Sopenharmony_ci#define INT_SIG_EN		0xc
4562306a36Sopenharmony_ci#define INT_STS_ALL		GENMASK(31, 0)
4662306a36Sopenharmony_ci#define INT_RDY_PIN		BIT(26)
4762306a36Sopenharmony_ci#define INT_RDY_SR		BIT(25)
4862306a36Sopenharmony_ci#define INT_LNR_SUSP		BIT(24)
4962306a36Sopenharmony_ci#define INT_ECC_ERR		BIT(17)
5062306a36Sopenharmony_ci#define INT_CRC_ERR		BIT(16)
5162306a36Sopenharmony_ci#define INT_LWR_DIS		BIT(12)
5262306a36Sopenharmony_ci#define INT_LRD_DIS		BIT(11)
5362306a36Sopenharmony_ci#define INT_SDMA_INT		BIT(10)
5462306a36Sopenharmony_ci#define INT_DMA_FINISH		BIT(9)
5562306a36Sopenharmony_ci#define INT_RX_NOT_FULL		BIT(3)
5662306a36Sopenharmony_ci#define INT_RX_NOT_EMPTY	BIT(2)
5762306a36Sopenharmony_ci#define INT_TX_NOT_FULL		BIT(1)
5862306a36Sopenharmony_ci#define INT_TX_EMPTY		BIT(0)
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci#define HC_EN			0x10
6162306a36Sopenharmony_ci#define HC_EN_BIT		BIT(0)
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci#define TXD(x)			(0x14 + ((x) * 4))
6462306a36Sopenharmony_ci#define RXD			0x24
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci#define SS_CTRL(s)		(0x30 + ((s) * 4))
6762306a36Sopenharmony_ci#define LRD_CFG			0x44
6862306a36Sopenharmony_ci#define LWR_CFG			0x80
6962306a36Sopenharmony_ci#define RWW_CFG			0x70
7062306a36Sopenharmony_ci#define OP_READ			BIT(23)
7162306a36Sopenharmony_ci#define OP_DUMMY_CYC(x)		((x) << 17)
7262306a36Sopenharmony_ci#define OP_ADDR_BYTES(x)	((x) << 14)
7362306a36Sopenharmony_ci#define OP_CMD_BYTES(x)		(((x) - 1) << 13)
7462306a36Sopenharmony_ci#define OP_OCTA_CRC_EN		BIT(12)
7562306a36Sopenharmony_ci#define OP_DQS_EN		BIT(11)
7662306a36Sopenharmony_ci#define OP_ENHC_EN		BIT(10)
7762306a36Sopenharmony_ci#define OP_PREAMBLE_EN		BIT(9)
7862306a36Sopenharmony_ci#define OP_DATA_DDR		BIT(8)
7962306a36Sopenharmony_ci#define OP_DATA_BUSW(x)		((x) << 6)
8062306a36Sopenharmony_ci#define OP_ADDR_DDR		BIT(5)
8162306a36Sopenharmony_ci#define OP_ADDR_BUSW(x)		((x) << 3)
8262306a36Sopenharmony_ci#define OP_CMD_DDR		BIT(2)
8362306a36Sopenharmony_ci#define OP_CMD_BUSW(x)		(x)
8462306a36Sopenharmony_ci#define OP_BUSW_1		0
8562306a36Sopenharmony_ci#define OP_BUSW_2		1
8662306a36Sopenharmony_ci#define OP_BUSW_4		2
8762306a36Sopenharmony_ci#define OP_BUSW_8		3
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci#define OCTA_CRC		0x38
9062306a36Sopenharmony_ci#define OCTA_CRC_IN_EN(s)	BIT(3 + ((s) * 16))
9162306a36Sopenharmony_ci#define OCTA_CRC_CHUNK(s, x)	((fls((x) / 32)) << (1 + ((s) * 16)))
9262306a36Sopenharmony_ci#define OCTA_CRC_OUT_EN(s)	BIT(0 + ((s) * 16))
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci#define ONFI_DIN_CNT(s)		(0x3c + (s))
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci#define LRD_CTRL		0x48
9762306a36Sopenharmony_ci#define RWW_CTRL		0x74
9862306a36Sopenharmony_ci#define LWR_CTRL		0x84
9962306a36Sopenharmony_ci#define LMODE_EN		BIT(31)
10062306a36Sopenharmony_ci#define LMODE_SLV_ACT(x)	((x) << 21)
10162306a36Sopenharmony_ci#define LMODE_CMD1(x)		((x) << 8)
10262306a36Sopenharmony_ci#define LMODE_CMD0(x)		(x)
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci#define LRD_ADDR		0x4c
10562306a36Sopenharmony_ci#define LWR_ADDR		0x88
10662306a36Sopenharmony_ci#define LRD_RANGE		0x50
10762306a36Sopenharmony_ci#define LWR_RANGE		0x8c
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci#define AXI_SLV_ADDR		0x54
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci#define DMAC_RD_CFG		0x58
11262306a36Sopenharmony_ci#define DMAC_WR_CFG		0x94
11362306a36Sopenharmony_ci#define DMAC_CFG_PERIPH_EN	BIT(31)
11462306a36Sopenharmony_ci#define DMAC_CFG_ALLFLUSH_EN	BIT(30)
11562306a36Sopenharmony_ci#define DMAC_CFG_LASTFLUSH_EN	BIT(29)
11662306a36Sopenharmony_ci#define DMAC_CFG_QE(x)		(((x) + 1) << 16)
11762306a36Sopenharmony_ci#define DMAC_CFG_BURST_LEN(x)	(((x) + 1) << 12)
11862306a36Sopenharmony_ci#define DMAC_CFG_BURST_SZ(x)	((x) << 8)
11962306a36Sopenharmony_ci#define DMAC_CFG_DIR_READ	BIT(1)
12062306a36Sopenharmony_ci#define DMAC_CFG_START		BIT(0)
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci#define DMAC_RD_CNT		0x5c
12362306a36Sopenharmony_ci#define DMAC_WR_CNT		0x98
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci#define SDMA_ADDR		0x60
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci#define DMAM_CFG		0x64
12862306a36Sopenharmony_ci#define DMAM_CFG_START		BIT(31)
12962306a36Sopenharmony_ci#define DMAM_CFG_CONT		BIT(30)
13062306a36Sopenharmony_ci#define DMAM_CFG_SDMA_GAP(x)	(fls((x) / 8192) << 2)
13162306a36Sopenharmony_ci#define DMAM_CFG_DIR_READ	BIT(1)
13262306a36Sopenharmony_ci#define DMAM_CFG_EN		BIT(0)
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci#define DMAM_CNT		0x68
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci#define LNR_TIMER_TH		0x6c
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci#define RDM_CFG0		0x78
13962306a36Sopenharmony_ci#define RDM_CFG0_POLY(x)	(x)
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci#define RDM_CFG1		0x7c
14262306a36Sopenharmony_ci#define RDM_CFG1_RDM_EN		BIT(31)
14362306a36Sopenharmony_ci#define RDM_CFG1_SEED(x)	(x)
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci#define LWR_SUSP_CTRL		0x90
14662306a36Sopenharmony_ci#define LWR_SUSP_CTRL_EN	BIT(31)
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci#define DMAS_CTRL		0x9c
14962306a36Sopenharmony_ci#define DMAS_CTRL_EN		BIT(31)
15062306a36Sopenharmony_ci#define DMAS_CTRL_DIR_READ	BIT(30)
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci#define DATA_STROB		0xa0
15362306a36Sopenharmony_ci#define DATA_STROB_EDO_EN	BIT(2)
15462306a36Sopenharmony_ci#define DATA_STROB_INV_POL	BIT(1)
15562306a36Sopenharmony_ci#define DATA_STROB_DELAY_2CYC	BIT(0)
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci#define IDLY_CODE(x)		(0xa4 + ((x) * 4))
15862306a36Sopenharmony_ci#define IDLY_CODE_VAL(x, v)	((v) << (((x) % 4) * 8))
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci#define GPIO			0xc4
16162306a36Sopenharmony_ci#define GPIO_PT(x)		BIT(3 + ((x) * 16))
16262306a36Sopenharmony_ci#define GPIO_RESET(x)		BIT(2 + ((x) * 16))
16362306a36Sopenharmony_ci#define GPIO_HOLDB(x)		BIT(1 + ((x) * 16))
16462306a36Sopenharmony_ci#define GPIO_WPB(x)		BIT((x) * 16)
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci#define HC_VER			0xd0
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci#define HW_TEST(x)		(0xe0 + ((x) * 4))
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci#define MXIC_NFC_MAX_CLK_HZ	50000000
17162306a36Sopenharmony_ci#define IRQ_TIMEOUT		1000
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_cistruct mxic_nand_ctlr {
17462306a36Sopenharmony_ci	struct clk *ps_clk;
17562306a36Sopenharmony_ci	struct clk *send_clk;
17662306a36Sopenharmony_ci	struct clk *send_dly_clk;
17762306a36Sopenharmony_ci	struct completion complete;
17862306a36Sopenharmony_ci	void __iomem *regs;
17962306a36Sopenharmony_ci	struct nand_controller controller;
18062306a36Sopenharmony_ci	struct device *dev;
18162306a36Sopenharmony_ci	struct nand_chip chip;
18262306a36Sopenharmony_ci};
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_cistatic int mxic_nfc_clk_enable(struct mxic_nand_ctlr *nfc)
18562306a36Sopenharmony_ci{
18662306a36Sopenharmony_ci	int ret;
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	ret = clk_prepare_enable(nfc->ps_clk);
18962306a36Sopenharmony_ci	if (ret)
19062306a36Sopenharmony_ci		return ret;
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	ret = clk_prepare_enable(nfc->send_clk);
19362306a36Sopenharmony_ci	if (ret)
19462306a36Sopenharmony_ci		goto err_ps_clk;
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	ret = clk_prepare_enable(nfc->send_dly_clk);
19762306a36Sopenharmony_ci	if (ret)
19862306a36Sopenharmony_ci		goto err_send_dly_clk;
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	return ret;
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_cierr_send_dly_clk:
20362306a36Sopenharmony_ci	clk_disable_unprepare(nfc->send_clk);
20462306a36Sopenharmony_cierr_ps_clk:
20562306a36Sopenharmony_ci	clk_disable_unprepare(nfc->ps_clk);
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	return ret;
20862306a36Sopenharmony_ci}
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_cistatic void mxic_nfc_clk_disable(struct mxic_nand_ctlr *nfc)
21162306a36Sopenharmony_ci{
21262306a36Sopenharmony_ci	clk_disable_unprepare(nfc->send_clk);
21362306a36Sopenharmony_ci	clk_disable_unprepare(nfc->send_dly_clk);
21462306a36Sopenharmony_ci	clk_disable_unprepare(nfc->ps_clk);
21562306a36Sopenharmony_ci}
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_cistatic void mxic_nfc_set_input_delay(struct mxic_nand_ctlr *nfc, u8 idly_code)
21862306a36Sopenharmony_ci{
21962306a36Sopenharmony_ci	writel(IDLY_CODE_VAL(0, idly_code) |
22062306a36Sopenharmony_ci	       IDLY_CODE_VAL(1, idly_code) |
22162306a36Sopenharmony_ci	       IDLY_CODE_VAL(2, idly_code) |
22262306a36Sopenharmony_ci	       IDLY_CODE_VAL(3, idly_code),
22362306a36Sopenharmony_ci	       nfc->regs + IDLY_CODE(0));
22462306a36Sopenharmony_ci	writel(IDLY_CODE_VAL(4, idly_code) |
22562306a36Sopenharmony_ci	       IDLY_CODE_VAL(5, idly_code) |
22662306a36Sopenharmony_ci	       IDLY_CODE_VAL(6, idly_code) |
22762306a36Sopenharmony_ci	       IDLY_CODE_VAL(7, idly_code),
22862306a36Sopenharmony_ci	       nfc->regs + IDLY_CODE(1));
22962306a36Sopenharmony_ci}
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_cistatic int mxic_nfc_clk_setup(struct mxic_nand_ctlr *nfc, unsigned long freq)
23262306a36Sopenharmony_ci{
23362306a36Sopenharmony_ci	int ret;
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	ret = clk_set_rate(nfc->send_clk, freq);
23662306a36Sopenharmony_ci	if (ret)
23762306a36Sopenharmony_ci		return ret;
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	ret = clk_set_rate(nfc->send_dly_clk, freq);
24062306a36Sopenharmony_ci	if (ret)
24162306a36Sopenharmony_ci		return ret;
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	/*
24462306a36Sopenharmony_ci	 * A constant delay range from 0x0 ~ 0x1F for input delay,
24562306a36Sopenharmony_ci	 * the unit is 78 ps, the max input delay is 2.418 ns.
24662306a36Sopenharmony_ci	 */
24762306a36Sopenharmony_ci	mxic_nfc_set_input_delay(nfc, 0xf);
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	/*
25062306a36Sopenharmony_ci	 * Phase degree = 360 * freq * output-delay
25162306a36Sopenharmony_ci	 * where output-delay is a constant value 1 ns in FPGA.
25262306a36Sopenharmony_ci	 *
25362306a36Sopenharmony_ci	 * Get Phase degree = 360 * freq * 1 ns
25462306a36Sopenharmony_ci	 *                  = 360 * freq * 1 sec / 1000000000
25562306a36Sopenharmony_ci	 *                  = 9 * freq / 25000000
25662306a36Sopenharmony_ci	 */
25762306a36Sopenharmony_ci	ret = clk_set_phase(nfc->send_dly_clk, 9 * freq / 25000000);
25862306a36Sopenharmony_ci	if (ret)
25962306a36Sopenharmony_ci		return ret;
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	return 0;
26262306a36Sopenharmony_ci}
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_cistatic int mxic_nfc_set_freq(struct mxic_nand_ctlr *nfc, unsigned long freq)
26562306a36Sopenharmony_ci{
26662306a36Sopenharmony_ci	int ret;
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	if (freq > MXIC_NFC_MAX_CLK_HZ)
26962306a36Sopenharmony_ci		freq = MXIC_NFC_MAX_CLK_HZ;
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	mxic_nfc_clk_disable(nfc);
27262306a36Sopenharmony_ci	ret = mxic_nfc_clk_setup(nfc, freq);
27362306a36Sopenharmony_ci	if (ret)
27462306a36Sopenharmony_ci		return ret;
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	ret = mxic_nfc_clk_enable(nfc);
27762306a36Sopenharmony_ci	if (ret)
27862306a36Sopenharmony_ci		return ret;
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	return 0;
28162306a36Sopenharmony_ci}
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_cistatic irqreturn_t mxic_nfc_isr(int irq, void *dev_id)
28462306a36Sopenharmony_ci{
28562306a36Sopenharmony_ci	struct mxic_nand_ctlr *nfc = dev_id;
28662306a36Sopenharmony_ci	u32 sts;
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	sts = readl(nfc->regs + INT_STS);
28962306a36Sopenharmony_ci	if (sts & INT_RDY_PIN)
29062306a36Sopenharmony_ci		complete(&nfc->complete);
29162306a36Sopenharmony_ci	else
29262306a36Sopenharmony_ci		return IRQ_NONE;
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	return IRQ_HANDLED;
29562306a36Sopenharmony_ci}
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_cistatic void mxic_nfc_hw_init(struct mxic_nand_ctlr *nfc)
29862306a36Sopenharmony_ci{
29962306a36Sopenharmony_ci	writel(HC_CFG_NIO(8) | HC_CFG_TYPE(1, HC_CFG_TYPE_RAW_NAND) |
30062306a36Sopenharmony_ci	       HC_CFG_SLV_ACT(0) | HC_CFG_MAN_CS_EN |
30162306a36Sopenharmony_ci	       HC_CFG_IDLE_SIO_LVL(1), nfc->regs + HC_CFG);
30262306a36Sopenharmony_ci	writel(INT_STS_ALL, nfc->regs + INT_STS_EN);
30362306a36Sopenharmony_ci	writel(INT_RDY_PIN, nfc->regs + INT_SIG_EN);
30462306a36Sopenharmony_ci	writel(0x0, nfc->regs + ONFI_DIN_CNT(0));
30562306a36Sopenharmony_ci	writel(0, nfc->regs + LRD_CFG);
30662306a36Sopenharmony_ci	writel(0, nfc->regs + LRD_CTRL);
30762306a36Sopenharmony_ci	writel(0x0, nfc->regs + HC_EN);
30862306a36Sopenharmony_ci}
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_cistatic void mxic_nfc_cs_enable(struct mxic_nand_ctlr *nfc)
31162306a36Sopenharmony_ci{
31262306a36Sopenharmony_ci	writel(readl(nfc->regs + HC_CFG) | HC_CFG_MAN_CS_EN,
31362306a36Sopenharmony_ci	       nfc->regs + HC_CFG);
31462306a36Sopenharmony_ci	writel(HC_CFG_MAN_CS_ASSERT | readl(nfc->regs + HC_CFG),
31562306a36Sopenharmony_ci	       nfc->regs + HC_CFG);
31662306a36Sopenharmony_ci}
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_cistatic void mxic_nfc_cs_disable(struct mxic_nand_ctlr *nfc)
31962306a36Sopenharmony_ci{
32062306a36Sopenharmony_ci	writel(~HC_CFG_MAN_CS_ASSERT & readl(nfc->regs + HC_CFG),
32162306a36Sopenharmony_ci	       nfc->regs + HC_CFG);
32262306a36Sopenharmony_ci}
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_cistatic int  mxic_nfc_wait_ready(struct nand_chip *chip)
32562306a36Sopenharmony_ci{
32662306a36Sopenharmony_ci	struct mxic_nand_ctlr *nfc = nand_get_controller_data(chip);
32762306a36Sopenharmony_ci	int ret;
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	ret = wait_for_completion_timeout(&nfc->complete,
33062306a36Sopenharmony_ci					  msecs_to_jiffies(IRQ_TIMEOUT));
33162306a36Sopenharmony_ci	if (!ret) {
33262306a36Sopenharmony_ci		dev_err(nfc->dev, "nand device timeout\n");
33362306a36Sopenharmony_ci		return -ETIMEDOUT;
33462306a36Sopenharmony_ci	}
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	return 0;
33762306a36Sopenharmony_ci}
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_cistatic int mxic_nfc_data_xfer(struct mxic_nand_ctlr *nfc, const void *txbuf,
34062306a36Sopenharmony_ci			      void *rxbuf, unsigned int len)
34162306a36Sopenharmony_ci{
34262306a36Sopenharmony_ci	unsigned int pos = 0;
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	while (pos < len) {
34562306a36Sopenharmony_ci		unsigned int nbytes = len - pos;
34662306a36Sopenharmony_ci		u32 data = 0xffffffff;
34762306a36Sopenharmony_ci		u32 sts;
34862306a36Sopenharmony_ci		int ret;
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci		if (nbytes > 4)
35162306a36Sopenharmony_ci			nbytes = 4;
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci		if (txbuf)
35462306a36Sopenharmony_ci			memcpy(&data, txbuf + pos, nbytes);
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci		ret = readl_poll_timeout(nfc->regs + INT_STS, sts,
35762306a36Sopenharmony_ci					 sts & INT_TX_EMPTY, 0, USEC_PER_SEC);
35862306a36Sopenharmony_ci		if (ret)
35962306a36Sopenharmony_ci			return ret;
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci		writel(data, nfc->regs + TXD(nbytes % 4));
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci		ret = readl_poll_timeout(nfc->regs + INT_STS, sts,
36462306a36Sopenharmony_ci					 sts & INT_TX_EMPTY, 0, USEC_PER_SEC);
36562306a36Sopenharmony_ci		if (ret)
36662306a36Sopenharmony_ci			return ret;
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci		ret = readl_poll_timeout(nfc->regs + INT_STS, sts,
36962306a36Sopenharmony_ci					 sts & INT_RX_NOT_EMPTY, 0,
37062306a36Sopenharmony_ci					 USEC_PER_SEC);
37162306a36Sopenharmony_ci		if (ret)
37262306a36Sopenharmony_ci			return ret;
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci		data = readl(nfc->regs + RXD);
37562306a36Sopenharmony_ci		if (rxbuf) {
37662306a36Sopenharmony_ci			data >>= (8 * (4 - nbytes));
37762306a36Sopenharmony_ci			memcpy(rxbuf + pos, &data, nbytes);
37862306a36Sopenharmony_ci		}
37962306a36Sopenharmony_ci		if (readl(nfc->regs + INT_STS) & INT_RX_NOT_EMPTY)
38062306a36Sopenharmony_ci			dev_warn(nfc->dev, "RX FIFO not empty\n");
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci		pos += nbytes;
38362306a36Sopenharmony_ci	}
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	return 0;
38662306a36Sopenharmony_ci}
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_cistatic int mxic_nfc_exec_op(struct nand_chip *chip,
38962306a36Sopenharmony_ci			    const struct nand_operation *op, bool check_only)
39062306a36Sopenharmony_ci{
39162306a36Sopenharmony_ci	struct mxic_nand_ctlr *nfc = nand_get_controller_data(chip);
39262306a36Sopenharmony_ci	const struct nand_op_instr *instr = NULL;
39362306a36Sopenharmony_ci	int ret = 0;
39462306a36Sopenharmony_ci	unsigned int op_id;
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	if (check_only)
39762306a36Sopenharmony_ci		return 0;
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	mxic_nfc_cs_enable(nfc);
40062306a36Sopenharmony_ci	init_completion(&nfc->complete);
40162306a36Sopenharmony_ci	for (op_id = 0; op_id < op->ninstrs; op_id++) {
40262306a36Sopenharmony_ci		instr = &op->instrs[op_id];
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci		switch (instr->type) {
40562306a36Sopenharmony_ci		case NAND_OP_CMD_INSTR:
40662306a36Sopenharmony_ci			writel(0, nfc->regs + HC_EN);
40762306a36Sopenharmony_ci			writel(HC_EN_BIT, nfc->regs + HC_EN);
40862306a36Sopenharmony_ci			writel(OP_CMD_BUSW(OP_BUSW_8) |  OP_DUMMY_CYC(0x3F) |
40962306a36Sopenharmony_ci			       OP_CMD_BYTES(0), nfc->regs + SS_CTRL(0));
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci			ret = mxic_nfc_data_xfer(nfc,
41262306a36Sopenharmony_ci						 &instr->ctx.cmd.opcode,
41362306a36Sopenharmony_ci						 NULL, 1);
41462306a36Sopenharmony_ci			break;
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci		case NAND_OP_ADDR_INSTR:
41762306a36Sopenharmony_ci			writel(OP_ADDR_BUSW(OP_BUSW_8) | OP_DUMMY_CYC(0x3F) |
41862306a36Sopenharmony_ci			       OP_ADDR_BYTES(instr->ctx.addr.naddrs),
41962306a36Sopenharmony_ci			       nfc->regs + SS_CTRL(0));
42062306a36Sopenharmony_ci			ret = mxic_nfc_data_xfer(nfc,
42162306a36Sopenharmony_ci						 instr->ctx.addr.addrs, NULL,
42262306a36Sopenharmony_ci						 instr->ctx.addr.naddrs);
42362306a36Sopenharmony_ci			break;
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci		case NAND_OP_DATA_IN_INSTR:
42662306a36Sopenharmony_ci			writel(0x0, nfc->regs + ONFI_DIN_CNT(0));
42762306a36Sopenharmony_ci			writel(OP_DATA_BUSW(OP_BUSW_8) | OP_DUMMY_CYC(0x3F) |
42862306a36Sopenharmony_ci			       OP_READ, nfc->regs + SS_CTRL(0));
42962306a36Sopenharmony_ci			ret = mxic_nfc_data_xfer(nfc, NULL,
43062306a36Sopenharmony_ci						 instr->ctx.data.buf.in,
43162306a36Sopenharmony_ci						 instr->ctx.data.len);
43262306a36Sopenharmony_ci			break;
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci		case NAND_OP_DATA_OUT_INSTR:
43562306a36Sopenharmony_ci			writel(instr->ctx.data.len,
43662306a36Sopenharmony_ci			       nfc->regs + ONFI_DIN_CNT(0));
43762306a36Sopenharmony_ci			writel(OP_DATA_BUSW(OP_BUSW_8) | OP_DUMMY_CYC(0x3F),
43862306a36Sopenharmony_ci			       nfc->regs + SS_CTRL(0));
43962306a36Sopenharmony_ci			ret = mxic_nfc_data_xfer(nfc,
44062306a36Sopenharmony_ci						 instr->ctx.data.buf.out, NULL,
44162306a36Sopenharmony_ci						 instr->ctx.data.len);
44262306a36Sopenharmony_ci			break;
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci		case NAND_OP_WAITRDY_INSTR:
44562306a36Sopenharmony_ci			ret = mxic_nfc_wait_ready(chip);
44662306a36Sopenharmony_ci			break;
44762306a36Sopenharmony_ci		}
44862306a36Sopenharmony_ci	}
44962306a36Sopenharmony_ci	mxic_nfc_cs_disable(nfc);
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	return ret;
45262306a36Sopenharmony_ci}
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_cistatic int mxic_nfc_setup_interface(struct nand_chip *chip, int chipnr,
45562306a36Sopenharmony_ci				    const struct nand_interface_config *conf)
45662306a36Sopenharmony_ci{
45762306a36Sopenharmony_ci	struct mxic_nand_ctlr *nfc = nand_get_controller_data(chip);
45862306a36Sopenharmony_ci	const struct nand_sdr_timings *sdr;
45962306a36Sopenharmony_ci	unsigned long freq;
46062306a36Sopenharmony_ci	int ret;
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	sdr = nand_get_sdr_timings(conf);
46362306a36Sopenharmony_ci	if (IS_ERR(sdr))
46462306a36Sopenharmony_ci		return PTR_ERR(sdr);
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	if (chipnr == NAND_DATA_IFACE_CHECK_ONLY)
46762306a36Sopenharmony_ci		return 0;
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	freq = NSEC_PER_SEC / (sdr->tRC_min / 1000);
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	ret =  mxic_nfc_set_freq(nfc, freq);
47262306a36Sopenharmony_ci	if (ret)
47362306a36Sopenharmony_ci		dev_err(nfc->dev, "set freq:%ld failed\n", freq);
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	if (sdr->tRC_min < 30000)
47662306a36Sopenharmony_ci		writel(DATA_STROB_EDO_EN, nfc->regs + DATA_STROB);
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci	return 0;
47962306a36Sopenharmony_ci}
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_cistatic const struct nand_controller_ops mxic_nand_controller_ops = {
48262306a36Sopenharmony_ci	.exec_op = mxic_nfc_exec_op,
48362306a36Sopenharmony_ci	.setup_interface = mxic_nfc_setup_interface,
48462306a36Sopenharmony_ci};
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_cistatic int mxic_nfc_probe(struct platform_device *pdev)
48762306a36Sopenharmony_ci{
48862306a36Sopenharmony_ci	struct device_node *nand_np, *np = pdev->dev.of_node;
48962306a36Sopenharmony_ci	struct mtd_info *mtd;
49062306a36Sopenharmony_ci	struct mxic_nand_ctlr *nfc;
49162306a36Sopenharmony_ci	struct nand_chip *nand_chip;
49262306a36Sopenharmony_ci	int err;
49362306a36Sopenharmony_ci	int irq;
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci	nfc = devm_kzalloc(&pdev->dev, sizeof(struct mxic_nand_ctlr),
49662306a36Sopenharmony_ci			   GFP_KERNEL);
49762306a36Sopenharmony_ci	if (!nfc)
49862306a36Sopenharmony_ci		return -ENOMEM;
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci	nfc->ps_clk = devm_clk_get(&pdev->dev, "ps");
50162306a36Sopenharmony_ci	if (IS_ERR(nfc->ps_clk))
50262306a36Sopenharmony_ci		return PTR_ERR(nfc->ps_clk);
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	nfc->send_clk = devm_clk_get(&pdev->dev, "send");
50562306a36Sopenharmony_ci	if (IS_ERR(nfc->send_clk))
50662306a36Sopenharmony_ci		return PTR_ERR(nfc->send_clk);
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci	nfc->send_dly_clk = devm_clk_get(&pdev->dev, "send_dly");
50962306a36Sopenharmony_ci	if (IS_ERR(nfc->send_dly_clk))
51062306a36Sopenharmony_ci		return PTR_ERR(nfc->send_dly_clk);
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	nfc->regs = devm_platform_ioremap_resource(pdev, 0);
51362306a36Sopenharmony_ci	if (IS_ERR(nfc->regs))
51462306a36Sopenharmony_ci		return PTR_ERR(nfc->regs);
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	nand_chip = &nfc->chip;
51762306a36Sopenharmony_ci	mtd = nand_to_mtd(nand_chip);
51862306a36Sopenharmony_ci	mtd->dev.parent = &pdev->dev;
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	for_each_child_of_node(np, nand_np)
52162306a36Sopenharmony_ci		nand_set_flash_node(nand_chip, nand_np);
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	nand_chip->priv = nfc;
52462306a36Sopenharmony_ci	nfc->dev = &pdev->dev;
52562306a36Sopenharmony_ci	nfc->controller.ops = &mxic_nand_controller_ops;
52662306a36Sopenharmony_ci	nand_controller_init(&nfc->controller);
52762306a36Sopenharmony_ci	nand_chip->controller = &nfc->controller;
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	irq = platform_get_irq(pdev, 0);
53062306a36Sopenharmony_ci	if (irq < 0)
53162306a36Sopenharmony_ci		return irq;
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	mxic_nfc_hw_init(nfc);
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci	err = devm_request_irq(&pdev->dev, irq, mxic_nfc_isr,
53662306a36Sopenharmony_ci			       0, "mxic-nfc", nfc);
53762306a36Sopenharmony_ci	if (err)
53862306a36Sopenharmony_ci		goto fail;
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	err = nand_scan(nand_chip, 1);
54162306a36Sopenharmony_ci	if (err)
54262306a36Sopenharmony_ci		goto fail;
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci	err = mtd_device_register(mtd, NULL, 0);
54562306a36Sopenharmony_ci	if (err)
54662306a36Sopenharmony_ci		goto fail;
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci	platform_set_drvdata(pdev, nfc);
54962306a36Sopenharmony_ci	return 0;
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_cifail:
55262306a36Sopenharmony_ci	mxic_nfc_clk_disable(nfc);
55362306a36Sopenharmony_ci	return err;
55462306a36Sopenharmony_ci}
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_cistatic void mxic_nfc_remove(struct platform_device *pdev)
55762306a36Sopenharmony_ci{
55862306a36Sopenharmony_ci	struct mxic_nand_ctlr *nfc = platform_get_drvdata(pdev);
55962306a36Sopenharmony_ci	struct nand_chip *chip = &nfc->chip;
56062306a36Sopenharmony_ci	int ret;
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci	ret = mtd_device_unregister(nand_to_mtd(chip));
56362306a36Sopenharmony_ci	WARN_ON(ret);
56462306a36Sopenharmony_ci	nand_cleanup(chip);
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci	mxic_nfc_clk_disable(nfc);
56762306a36Sopenharmony_ci}
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_cistatic const struct of_device_id mxic_nfc_of_ids[] = {
57062306a36Sopenharmony_ci	{ .compatible = "mxic,multi-itfc-v009-nand-controller", },
57162306a36Sopenharmony_ci	{},
57262306a36Sopenharmony_ci};
57362306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, mxic_nfc_of_ids);
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_cistatic struct platform_driver mxic_nfc_driver = {
57662306a36Sopenharmony_ci	.probe = mxic_nfc_probe,
57762306a36Sopenharmony_ci	.remove_new = mxic_nfc_remove,
57862306a36Sopenharmony_ci	.driver = {
57962306a36Sopenharmony_ci		.name = "mxic-nfc",
58062306a36Sopenharmony_ci		.of_match_table = mxic_nfc_of_ids,
58162306a36Sopenharmony_ci	},
58262306a36Sopenharmony_ci};
58362306a36Sopenharmony_cimodule_platform_driver(mxic_nfc_driver);
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ciMODULE_AUTHOR("Mason Yang <masonccyang@mxic.com.tw>");
58662306a36Sopenharmony_ciMODULE_DESCRIPTION("Macronix raw NAND controller driver");
58762306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
588