xref: /OK3568_Linux_fs/kernel/drivers/mtd/nand/raw/sunxi_nand.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0+
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright (C) 2013 Boris BREZILLON <b.brezillon.dev@gmail.com>
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Derived from:
6*4882a593Smuzhiyun  *	https://github.com/yuq/sunxi-nfc-mtd
7*4882a593Smuzhiyun  *	Copyright (C) 2013 Qiang Yu <yuq825@gmail.com>
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  *	https://github.com/hno/Allwinner-Info
10*4882a593Smuzhiyun  *	Copyright (C) 2013 Henrik Nordström <Henrik Nordström>
11*4882a593Smuzhiyun  *
12*4882a593Smuzhiyun  *	Copyright (C) 2013 Dmitriy B. <rzk333@gmail.com>
13*4882a593Smuzhiyun  *	Copyright (C) 2013 Sergey Lapin <slapin@ossfans.org>
14*4882a593Smuzhiyun  */
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun #include <linux/dma-mapping.h>
17*4882a593Smuzhiyun #include <linux/slab.h>
18*4882a593Smuzhiyun #include <linux/module.h>
19*4882a593Smuzhiyun #include <linux/moduleparam.h>
20*4882a593Smuzhiyun #include <linux/platform_device.h>
21*4882a593Smuzhiyun #include <linux/of.h>
22*4882a593Smuzhiyun #include <linux/of_device.h>
23*4882a593Smuzhiyun #include <linux/mtd/mtd.h>
24*4882a593Smuzhiyun #include <linux/mtd/rawnand.h>
25*4882a593Smuzhiyun #include <linux/mtd/partitions.h>
26*4882a593Smuzhiyun #include <linux/clk.h>
27*4882a593Smuzhiyun #include <linux/delay.h>
28*4882a593Smuzhiyun #include <linux/dmaengine.h>
29*4882a593Smuzhiyun #include <linux/interrupt.h>
30*4882a593Smuzhiyun #include <linux/iopoll.h>
31*4882a593Smuzhiyun #include <linux/reset.h>
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun #define NFC_REG_CTL		0x0000
34*4882a593Smuzhiyun #define NFC_REG_ST		0x0004
35*4882a593Smuzhiyun #define NFC_REG_INT		0x0008
36*4882a593Smuzhiyun #define NFC_REG_TIMING_CTL	0x000C
37*4882a593Smuzhiyun #define NFC_REG_TIMING_CFG	0x0010
38*4882a593Smuzhiyun #define NFC_REG_ADDR_LOW	0x0014
39*4882a593Smuzhiyun #define NFC_REG_ADDR_HIGH	0x0018
40*4882a593Smuzhiyun #define NFC_REG_SECTOR_NUM	0x001C
41*4882a593Smuzhiyun #define NFC_REG_CNT		0x0020
42*4882a593Smuzhiyun #define NFC_REG_CMD		0x0024
43*4882a593Smuzhiyun #define NFC_REG_RCMD_SET	0x0028
44*4882a593Smuzhiyun #define NFC_REG_WCMD_SET	0x002C
45*4882a593Smuzhiyun #define NFC_REG_A10_IO_DATA	0x0030
46*4882a593Smuzhiyun #define NFC_REG_A23_IO_DATA	0x0300
47*4882a593Smuzhiyun #define NFC_REG_ECC_CTL		0x0034
48*4882a593Smuzhiyun #define NFC_REG_ECC_ST		0x0038
49*4882a593Smuzhiyun #define NFC_REG_DEBUG		0x003C
50*4882a593Smuzhiyun #define NFC_REG_ECC_ERR_CNT(x)	((0x0040 + (x)) & ~0x3)
51*4882a593Smuzhiyun #define NFC_REG_USER_DATA(x)	(0x0050 + ((x) * 4))
52*4882a593Smuzhiyun #define NFC_REG_SPARE_AREA	0x00A0
53*4882a593Smuzhiyun #define NFC_REG_PAT_ID		0x00A4
54*4882a593Smuzhiyun #define NFC_REG_MDMA_CNT	0x00C4
55*4882a593Smuzhiyun #define NFC_RAM0_BASE		0x0400
56*4882a593Smuzhiyun #define NFC_RAM1_BASE		0x0800
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun /* define bit use in NFC_CTL */
59*4882a593Smuzhiyun #define NFC_EN			BIT(0)
60*4882a593Smuzhiyun #define NFC_RESET		BIT(1)
61*4882a593Smuzhiyun #define NFC_BUS_WIDTH_MSK	BIT(2)
62*4882a593Smuzhiyun #define NFC_BUS_WIDTH_8		(0 << 2)
63*4882a593Smuzhiyun #define NFC_BUS_WIDTH_16	(1 << 2)
64*4882a593Smuzhiyun #define NFC_RB_SEL_MSK		BIT(3)
65*4882a593Smuzhiyun #define NFC_RB_SEL(x)		((x) << 3)
66*4882a593Smuzhiyun #define NFC_CE_SEL_MSK		GENMASK(26, 24)
67*4882a593Smuzhiyun #define NFC_CE_SEL(x)		((x) << 24)
68*4882a593Smuzhiyun #define NFC_CE_CTL		BIT(6)
69*4882a593Smuzhiyun #define NFC_PAGE_SHIFT_MSK	GENMASK(11, 8)
70*4882a593Smuzhiyun #define NFC_PAGE_SHIFT(x)	(((x) < 10 ? 0 : (x) - 10) << 8)
71*4882a593Smuzhiyun #define NFC_SAM			BIT(12)
72*4882a593Smuzhiyun #define NFC_RAM_METHOD		BIT(14)
73*4882a593Smuzhiyun #define NFC_DMA_TYPE_NORMAL	BIT(15)
74*4882a593Smuzhiyun #define NFC_DEBUG_CTL		BIT(31)
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun /* define bit use in NFC_ST */
77*4882a593Smuzhiyun #define NFC_RB_B2R		BIT(0)
78*4882a593Smuzhiyun #define NFC_CMD_INT_FLAG	BIT(1)
79*4882a593Smuzhiyun #define NFC_DMA_INT_FLAG	BIT(2)
80*4882a593Smuzhiyun #define NFC_CMD_FIFO_STATUS	BIT(3)
81*4882a593Smuzhiyun #define NFC_STA			BIT(4)
82*4882a593Smuzhiyun #define NFC_NATCH_INT_FLAG	BIT(5)
83*4882a593Smuzhiyun #define NFC_RB_STATE(x)		BIT(x + 8)
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun /* define bit use in NFC_INT */
86*4882a593Smuzhiyun #define NFC_B2R_INT_ENABLE	BIT(0)
87*4882a593Smuzhiyun #define NFC_CMD_INT_ENABLE	BIT(1)
88*4882a593Smuzhiyun #define NFC_DMA_INT_ENABLE	BIT(2)
89*4882a593Smuzhiyun #define NFC_INT_MASK		(NFC_B2R_INT_ENABLE | \
90*4882a593Smuzhiyun 				 NFC_CMD_INT_ENABLE | \
91*4882a593Smuzhiyun 				 NFC_DMA_INT_ENABLE)
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun /* define bit use in NFC_TIMING_CTL */
94*4882a593Smuzhiyun #define NFC_TIMING_CTL_EDO	BIT(8)
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun /* define NFC_TIMING_CFG register layout */
97*4882a593Smuzhiyun #define NFC_TIMING_CFG(tWB, tADL, tWHR, tRHW, tCAD)		\
98*4882a593Smuzhiyun 	(((tWB) & 0x3) | (((tADL) & 0x3) << 2) |		\
99*4882a593Smuzhiyun 	(((tWHR) & 0x3) << 4) | (((tRHW) & 0x3) << 6) |		\
100*4882a593Smuzhiyun 	(((tCAD) & 0x7) << 8))
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun /* define bit use in NFC_CMD */
103*4882a593Smuzhiyun #define NFC_CMD_LOW_BYTE_MSK	GENMASK(7, 0)
104*4882a593Smuzhiyun #define NFC_CMD_HIGH_BYTE_MSK	GENMASK(15, 8)
105*4882a593Smuzhiyun #define NFC_CMD(x)		(x)
106*4882a593Smuzhiyun #define NFC_ADR_NUM_MSK		GENMASK(18, 16)
107*4882a593Smuzhiyun #define NFC_ADR_NUM(x)		(((x) - 1) << 16)
108*4882a593Smuzhiyun #define NFC_SEND_ADR		BIT(19)
109*4882a593Smuzhiyun #define NFC_ACCESS_DIR		BIT(20)
110*4882a593Smuzhiyun #define NFC_DATA_TRANS		BIT(21)
111*4882a593Smuzhiyun #define NFC_SEND_CMD1		BIT(22)
112*4882a593Smuzhiyun #define NFC_WAIT_FLAG		BIT(23)
113*4882a593Smuzhiyun #define NFC_SEND_CMD2		BIT(24)
114*4882a593Smuzhiyun #define NFC_SEQ			BIT(25)
115*4882a593Smuzhiyun #define NFC_DATA_SWAP_METHOD	BIT(26)
116*4882a593Smuzhiyun #define NFC_ROW_AUTO_INC	BIT(27)
117*4882a593Smuzhiyun #define NFC_SEND_CMD3		BIT(28)
118*4882a593Smuzhiyun #define NFC_SEND_CMD4		BIT(29)
119*4882a593Smuzhiyun #define NFC_CMD_TYPE_MSK	GENMASK(31, 30)
120*4882a593Smuzhiyun #define NFC_NORMAL_OP		(0 << 30)
121*4882a593Smuzhiyun #define NFC_ECC_OP		(1 << 30)
122*4882a593Smuzhiyun #define NFC_PAGE_OP		(2U << 30)
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun /* define bit use in NFC_RCMD_SET */
125*4882a593Smuzhiyun #define NFC_READ_CMD_MSK	GENMASK(7, 0)
126*4882a593Smuzhiyun #define NFC_RND_READ_CMD0_MSK	GENMASK(15, 8)
127*4882a593Smuzhiyun #define NFC_RND_READ_CMD1_MSK	GENMASK(23, 16)
128*4882a593Smuzhiyun 
129*4882a593Smuzhiyun /* define bit use in NFC_WCMD_SET */
130*4882a593Smuzhiyun #define NFC_PROGRAM_CMD_MSK	GENMASK(7, 0)
131*4882a593Smuzhiyun #define NFC_RND_WRITE_CMD_MSK	GENMASK(15, 8)
132*4882a593Smuzhiyun #define NFC_READ_CMD0_MSK	GENMASK(23, 16)
133*4882a593Smuzhiyun #define NFC_READ_CMD1_MSK	GENMASK(31, 24)
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun /* define bit use in NFC_ECC_CTL */
136*4882a593Smuzhiyun #define NFC_ECC_EN		BIT(0)
137*4882a593Smuzhiyun #define NFC_ECC_PIPELINE	BIT(3)
138*4882a593Smuzhiyun #define NFC_ECC_EXCEPTION	BIT(4)
139*4882a593Smuzhiyun #define NFC_ECC_BLOCK_SIZE_MSK	BIT(5)
140*4882a593Smuzhiyun #define NFC_ECC_BLOCK_512	BIT(5)
141*4882a593Smuzhiyun #define NFC_RANDOM_EN		BIT(9)
142*4882a593Smuzhiyun #define NFC_RANDOM_DIRECTION	BIT(10)
143*4882a593Smuzhiyun #define NFC_ECC_MODE_MSK	GENMASK(15, 12)
144*4882a593Smuzhiyun #define NFC_ECC_MODE(x)		((x) << 12)
145*4882a593Smuzhiyun #define NFC_RANDOM_SEED_MSK	GENMASK(30, 16)
146*4882a593Smuzhiyun #define NFC_RANDOM_SEED(x)	((x) << 16)
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun /* define bit use in NFC_ECC_ST */
149*4882a593Smuzhiyun #define NFC_ECC_ERR(x)		BIT(x)
150*4882a593Smuzhiyun #define NFC_ECC_ERR_MSK		GENMASK(15, 0)
151*4882a593Smuzhiyun #define NFC_ECC_PAT_FOUND(x)	BIT(x + 16)
152*4882a593Smuzhiyun #define NFC_ECC_ERR_CNT(b, x)	(((x) >> (((b) % 4) * 8)) & 0xff)
153*4882a593Smuzhiyun 
154*4882a593Smuzhiyun #define NFC_DEFAULT_TIMEOUT_MS	1000
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun #define NFC_SRAM_SIZE		1024
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun #define NFC_MAX_CS		7
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun /**
161*4882a593Smuzhiyun  * struct sunxi_nand_chip_sel - stores information related to NAND Chip Select
162*4882a593Smuzhiyun  *
163*4882a593Smuzhiyun  * @cs: the NAND CS id used to communicate with a NAND Chip
164*4882a593Smuzhiyun  * @rb: the Ready/Busy pin ID. -1 means no R/B pin connected to the NFC
165*4882a593Smuzhiyun  */
166*4882a593Smuzhiyun struct sunxi_nand_chip_sel {
167*4882a593Smuzhiyun 	u8 cs;
168*4882a593Smuzhiyun 	s8 rb;
169*4882a593Smuzhiyun };
170*4882a593Smuzhiyun 
171*4882a593Smuzhiyun /**
172*4882a593Smuzhiyun  * struct sunxi_nand_hw_ecc - stores information related to HW ECC support
173*4882a593Smuzhiyun  *
174*4882a593Smuzhiyun  * @mode: the sunxi ECC mode field deduced from ECC requirements
175*4882a593Smuzhiyun  */
176*4882a593Smuzhiyun struct sunxi_nand_hw_ecc {
177*4882a593Smuzhiyun 	int mode;
178*4882a593Smuzhiyun };
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun /**
181*4882a593Smuzhiyun  * struct sunxi_nand_chip - stores NAND chip device related information
182*4882a593Smuzhiyun  *
183*4882a593Smuzhiyun  * @node: used to store NAND chips into a list
184*4882a593Smuzhiyun  * @nand: base NAND chip structure
185*4882a593Smuzhiyun  * @clk_rate: clk_rate required for this NAND chip
186*4882a593Smuzhiyun  * @timing_cfg: TIMING_CFG register value for this NAND chip
187*4882a593Smuzhiyun  * @timing_ctl: TIMING_CTL register value for this NAND chip
188*4882a593Smuzhiyun  * @nsels: number of CS lines required by the NAND chip
189*4882a593Smuzhiyun  * @sels: array of CS lines descriptions
190*4882a593Smuzhiyun  */
191*4882a593Smuzhiyun struct sunxi_nand_chip {
192*4882a593Smuzhiyun 	struct list_head node;
193*4882a593Smuzhiyun 	struct nand_chip nand;
194*4882a593Smuzhiyun 	unsigned long clk_rate;
195*4882a593Smuzhiyun 	u32 timing_cfg;
196*4882a593Smuzhiyun 	u32 timing_ctl;
197*4882a593Smuzhiyun 	int nsels;
198*4882a593Smuzhiyun 	struct sunxi_nand_chip_sel sels[];
199*4882a593Smuzhiyun };
200*4882a593Smuzhiyun 
to_sunxi_nand(struct nand_chip * nand)201*4882a593Smuzhiyun static inline struct sunxi_nand_chip *to_sunxi_nand(struct nand_chip *nand)
202*4882a593Smuzhiyun {
203*4882a593Smuzhiyun 	return container_of(nand, struct sunxi_nand_chip, nand);
204*4882a593Smuzhiyun }
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun /*
207*4882a593Smuzhiyun  * NAND Controller capabilities structure: stores NAND controller capabilities
208*4882a593Smuzhiyun  * for distinction between compatible strings.
209*4882a593Smuzhiyun  *
210*4882a593Smuzhiyun  * @extra_mbus_conf:	Contrary to A10, A10s and A13, accessing internal RAM
211*4882a593Smuzhiyun  *			through MBUS on A23/A33 needs extra configuration.
212*4882a593Smuzhiyun  * @reg_io_data:	I/O data register
213*4882a593Smuzhiyun  * @dma_maxburst:	DMA maxburst
214*4882a593Smuzhiyun  */
215*4882a593Smuzhiyun struct sunxi_nfc_caps {
216*4882a593Smuzhiyun 	bool extra_mbus_conf;
217*4882a593Smuzhiyun 	unsigned int reg_io_data;
218*4882a593Smuzhiyun 	unsigned int dma_maxburst;
219*4882a593Smuzhiyun };
220*4882a593Smuzhiyun 
221*4882a593Smuzhiyun /**
222*4882a593Smuzhiyun  * struct sunxi_nfc - stores sunxi NAND controller information
223*4882a593Smuzhiyun  *
224*4882a593Smuzhiyun  * @controller: base controller structure
225*4882a593Smuzhiyun  * @dev: parent device (used to print error messages)
226*4882a593Smuzhiyun  * @regs: NAND controller registers
227*4882a593Smuzhiyun  * @ahb_clk: NAND controller AHB clock
228*4882a593Smuzhiyun  * @mod_clk: NAND controller mod clock
229*4882a593Smuzhiyun  * @reset: NAND controller reset line
230*4882a593Smuzhiyun  * @assigned_cs: bitmask describing already assigned CS lines
231*4882a593Smuzhiyun  * @clk_rate: NAND controller current clock rate
232*4882a593Smuzhiyun  * @chips: a list containing all the NAND chips attached to this NAND
233*4882a593Smuzhiyun  *	   controller
234*4882a593Smuzhiyun  * @complete: a completion object used to wait for NAND controller events
235*4882a593Smuzhiyun  * @dmac: the DMA channel attached to the NAND controller
236*4882a593Smuzhiyun  */
237*4882a593Smuzhiyun struct sunxi_nfc {
238*4882a593Smuzhiyun 	struct nand_controller controller;
239*4882a593Smuzhiyun 	struct device *dev;
240*4882a593Smuzhiyun 	void __iomem *regs;
241*4882a593Smuzhiyun 	struct clk *ahb_clk;
242*4882a593Smuzhiyun 	struct clk *mod_clk;
243*4882a593Smuzhiyun 	struct reset_control *reset;
244*4882a593Smuzhiyun 	unsigned long assigned_cs;
245*4882a593Smuzhiyun 	unsigned long clk_rate;
246*4882a593Smuzhiyun 	struct list_head chips;
247*4882a593Smuzhiyun 	struct completion complete;
248*4882a593Smuzhiyun 	struct dma_chan *dmac;
249*4882a593Smuzhiyun 	const struct sunxi_nfc_caps *caps;
250*4882a593Smuzhiyun };
251*4882a593Smuzhiyun 
to_sunxi_nfc(struct nand_controller * ctrl)252*4882a593Smuzhiyun static inline struct sunxi_nfc *to_sunxi_nfc(struct nand_controller *ctrl)
253*4882a593Smuzhiyun {
254*4882a593Smuzhiyun 	return container_of(ctrl, struct sunxi_nfc, controller);
255*4882a593Smuzhiyun }
256*4882a593Smuzhiyun 
sunxi_nfc_interrupt(int irq,void * dev_id)257*4882a593Smuzhiyun static irqreturn_t sunxi_nfc_interrupt(int irq, void *dev_id)
258*4882a593Smuzhiyun {
259*4882a593Smuzhiyun 	struct sunxi_nfc *nfc = dev_id;
260*4882a593Smuzhiyun 	u32 st = readl(nfc->regs + NFC_REG_ST);
261*4882a593Smuzhiyun 	u32 ien = readl(nfc->regs + NFC_REG_INT);
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun 	if (!(ien & st))
264*4882a593Smuzhiyun 		return IRQ_NONE;
265*4882a593Smuzhiyun 
266*4882a593Smuzhiyun 	if ((ien & st) == ien)
267*4882a593Smuzhiyun 		complete(&nfc->complete);
268*4882a593Smuzhiyun 
269*4882a593Smuzhiyun 	writel(st & NFC_INT_MASK, nfc->regs + NFC_REG_ST);
270*4882a593Smuzhiyun 	writel(~st & ien & NFC_INT_MASK, nfc->regs + NFC_REG_INT);
271*4882a593Smuzhiyun 
272*4882a593Smuzhiyun 	return IRQ_HANDLED;
273*4882a593Smuzhiyun }
274*4882a593Smuzhiyun 
sunxi_nfc_wait_events(struct sunxi_nfc * nfc,u32 events,bool use_polling,unsigned int timeout_ms)275*4882a593Smuzhiyun static int sunxi_nfc_wait_events(struct sunxi_nfc *nfc, u32 events,
276*4882a593Smuzhiyun 				 bool use_polling, unsigned int timeout_ms)
277*4882a593Smuzhiyun {
278*4882a593Smuzhiyun 	int ret;
279*4882a593Smuzhiyun 
280*4882a593Smuzhiyun 	if (events & ~NFC_INT_MASK)
281*4882a593Smuzhiyun 		return -EINVAL;
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun 	if (!timeout_ms)
284*4882a593Smuzhiyun 		timeout_ms = NFC_DEFAULT_TIMEOUT_MS;
285*4882a593Smuzhiyun 
286*4882a593Smuzhiyun 	if (!use_polling) {
287*4882a593Smuzhiyun 		init_completion(&nfc->complete);
288*4882a593Smuzhiyun 
289*4882a593Smuzhiyun 		writel(events, nfc->regs + NFC_REG_INT);
290*4882a593Smuzhiyun 
291*4882a593Smuzhiyun 		ret = wait_for_completion_timeout(&nfc->complete,
292*4882a593Smuzhiyun 						msecs_to_jiffies(timeout_ms));
293*4882a593Smuzhiyun 		if (!ret)
294*4882a593Smuzhiyun 			ret = -ETIMEDOUT;
295*4882a593Smuzhiyun 		else
296*4882a593Smuzhiyun 			ret = 0;
297*4882a593Smuzhiyun 
298*4882a593Smuzhiyun 		writel(0, nfc->regs + NFC_REG_INT);
299*4882a593Smuzhiyun 	} else {
300*4882a593Smuzhiyun 		u32 status;
301*4882a593Smuzhiyun 
302*4882a593Smuzhiyun 		ret = readl_poll_timeout(nfc->regs + NFC_REG_ST, status,
303*4882a593Smuzhiyun 					 (status & events) == events, 1,
304*4882a593Smuzhiyun 					 timeout_ms * 1000);
305*4882a593Smuzhiyun 	}
306*4882a593Smuzhiyun 
307*4882a593Smuzhiyun 	writel(events & NFC_INT_MASK, nfc->regs + NFC_REG_ST);
308*4882a593Smuzhiyun 
309*4882a593Smuzhiyun 	if (ret)
310*4882a593Smuzhiyun 		dev_err(nfc->dev, "wait interrupt timedout\n");
311*4882a593Smuzhiyun 
312*4882a593Smuzhiyun 	return ret;
313*4882a593Smuzhiyun }
314*4882a593Smuzhiyun 
sunxi_nfc_wait_cmd_fifo_empty(struct sunxi_nfc * nfc)315*4882a593Smuzhiyun static int sunxi_nfc_wait_cmd_fifo_empty(struct sunxi_nfc *nfc)
316*4882a593Smuzhiyun {
317*4882a593Smuzhiyun 	u32 status;
318*4882a593Smuzhiyun 	int ret;
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun 	ret = readl_poll_timeout(nfc->regs + NFC_REG_ST, status,
321*4882a593Smuzhiyun 				 !(status & NFC_CMD_FIFO_STATUS), 1,
322*4882a593Smuzhiyun 				 NFC_DEFAULT_TIMEOUT_MS * 1000);
323*4882a593Smuzhiyun 	if (ret)
324*4882a593Smuzhiyun 		dev_err(nfc->dev, "wait for empty cmd FIFO timedout\n");
325*4882a593Smuzhiyun 
326*4882a593Smuzhiyun 	return ret;
327*4882a593Smuzhiyun }
328*4882a593Smuzhiyun 
sunxi_nfc_rst(struct sunxi_nfc * nfc)329*4882a593Smuzhiyun static int sunxi_nfc_rst(struct sunxi_nfc *nfc)
330*4882a593Smuzhiyun {
331*4882a593Smuzhiyun 	u32 ctl;
332*4882a593Smuzhiyun 	int ret;
333*4882a593Smuzhiyun 
334*4882a593Smuzhiyun 	writel(0, nfc->regs + NFC_REG_ECC_CTL);
335*4882a593Smuzhiyun 	writel(NFC_RESET, nfc->regs + NFC_REG_CTL);
336*4882a593Smuzhiyun 
337*4882a593Smuzhiyun 	ret = readl_poll_timeout(nfc->regs + NFC_REG_CTL, ctl,
338*4882a593Smuzhiyun 				 !(ctl & NFC_RESET), 1,
339*4882a593Smuzhiyun 				 NFC_DEFAULT_TIMEOUT_MS * 1000);
340*4882a593Smuzhiyun 	if (ret)
341*4882a593Smuzhiyun 		dev_err(nfc->dev, "wait for NAND controller reset timedout\n");
342*4882a593Smuzhiyun 
343*4882a593Smuzhiyun 	return ret;
344*4882a593Smuzhiyun }
345*4882a593Smuzhiyun 
sunxi_nfc_dma_op_prepare(struct sunxi_nfc * nfc,const void * buf,int chunksize,int nchunks,enum dma_data_direction ddir,struct scatterlist * sg)346*4882a593Smuzhiyun static int sunxi_nfc_dma_op_prepare(struct sunxi_nfc *nfc, const void *buf,
347*4882a593Smuzhiyun 				    int chunksize, int nchunks,
348*4882a593Smuzhiyun 				    enum dma_data_direction ddir,
349*4882a593Smuzhiyun 				    struct scatterlist *sg)
350*4882a593Smuzhiyun {
351*4882a593Smuzhiyun 	struct dma_async_tx_descriptor *dmad;
352*4882a593Smuzhiyun 	enum dma_transfer_direction tdir;
353*4882a593Smuzhiyun 	dma_cookie_t dmat;
354*4882a593Smuzhiyun 	int ret;
355*4882a593Smuzhiyun 
356*4882a593Smuzhiyun 	if (ddir == DMA_FROM_DEVICE)
357*4882a593Smuzhiyun 		tdir = DMA_DEV_TO_MEM;
358*4882a593Smuzhiyun 	else
359*4882a593Smuzhiyun 		tdir = DMA_MEM_TO_DEV;
360*4882a593Smuzhiyun 
361*4882a593Smuzhiyun 	sg_init_one(sg, buf, nchunks * chunksize);
362*4882a593Smuzhiyun 	ret = dma_map_sg(nfc->dev, sg, 1, ddir);
363*4882a593Smuzhiyun 	if (!ret)
364*4882a593Smuzhiyun 		return -ENOMEM;
365*4882a593Smuzhiyun 
366*4882a593Smuzhiyun 	dmad = dmaengine_prep_slave_sg(nfc->dmac, sg, 1, tdir, DMA_CTRL_ACK);
367*4882a593Smuzhiyun 	if (!dmad) {
368*4882a593Smuzhiyun 		ret = -EINVAL;
369*4882a593Smuzhiyun 		goto err_unmap_buf;
370*4882a593Smuzhiyun 	}
371*4882a593Smuzhiyun 
372*4882a593Smuzhiyun 	writel(readl(nfc->regs + NFC_REG_CTL) | NFC_RAM_METHOD,
373*4882a593Smuzhiyun 	       nfc->regs + NFC_REG_CTL);
374*4882a593Smuzhiyun 	writel(nchunks, nfc->regs + NFC_REG_SECTOR_NUM);
375*4882a593Smuzhiyun 	writel(chunksize, nfc->regs + NFC_REG_CNT);
376*4882a593Smuzhiyun 	if (nfc->caps->extra_mbus_conf)
377*4882a593Smuzhiyun 		writel(chunksize * nchunks, nfc->regs + NFC_REG_MDMA_CNT);
378*4882a593Smuzhiyun 
379*4882a593Smuzhiyun 	dmat = dmaengine_submit(dmad);
380*4882a593Smuzhiyun 
381*4882a593Smuzhiyun 	ret = dma_submit_error(dmat);
382*4882a593Smuzhiyun 	if (ret)
383*4882a593Smuzhiyun 		goto err_clr_dma_flag;
384*4882a593Smuzhiyun 
385*4882a593Smuzhiyun 	return 0;
386*4882a593Smuzhiyun 
387*4882a593Smuzhiyun err_clr_dma_flag:
388*4882a593Smuzhiyun 	writel(readl(nfc->regs + NFC_REG_CTL) & ~NFC_RAM_METHOD,
389*4882a593Smuzhiyun 	       nfc->regs + NFC_REG_CTL);
390*4882a593Smuzhiyun 
391*4882a593Smuzhiyun err_unmap_buf:
392*4882a593Smuzhiyun 	dma_unmap_sg(nfc->dev, sg, 1, ddir);
393*4882a593Smuzhiyun 	return ret;
394*4882a593Smuzhiyun }
395*4882a593Smuzhiyun 
sunxi_nfc_dma_op_cleanup(struct sunxi_nfc * nfc,enum dma_data_direction ddir,struct scatterlist * sg)396*4882a593Smuzhiyun static void sunxi_nfc_dma_op_cleanup(struct sunxi_nfc *nfc,
397*4882a593Smuzhiyun 				     enum dma_data_direction ddir,
398*4882a593Smuzhiyun 				     struct scatterlist *sg)
399*4882a593Smuzhiyun {
400*4882a593Smuzhiyun 	dma_unmap_sg(nfc->dev, sg, 1, ddir);
401*4882a593Smuzhiyun 	writel(readl(nfc->regs + NFC_REG_CTL) & ~NFC_RAM_METHOD,
402*4882a593Smuzhiyun 	       nfc->regs + NFC_REG_CTL);
403*4882a593Smuzhiyun }
404*4882a593Smuzhiyun 
sunxi_nfc_select_chip(struct nand_chip * nand,unsigned int cs)405*4882a593Smuzhiyun static void sunxi_nfc_select_chip(struct nand_chip *nand, unsigned int cs)
406*4882a593Smuzhiyun {
407*4882a593Smuzhiyun 	struct mtd_info *mtd = nand_to_mtd(nand);
408*4882a593Smuzhiyun 	struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
409*4882a593Smuzhiyun 	struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
410*4882a593Smuzhiyun 	struct sunxi_nand_chip_sel *sel;
411*4882a593Smuzhiyun 	u32 ctl;
412*4882a593Smuzhiyun 
413*4882a593Smuzhiyun 	if (cs > 0 && cs >= sunxi_nand->nsels)
414*4882a593Smuzhiyun 		return;
415*4882a593Smuzhiyun 
416*4882a593Smuzhiyun 	ctl = readl(nfc->regs + NFC_REG_CTL) &
417*4882a593Smuzhiyun 	      ~(NFC_PAGE_SHIFT_MSK | NFC_CE_SEL_MSK | NFC_RB_SEL_MSK | NFC_EN);
418*4882a593Smuzhiyun 
419*4882a593Smuzhiyun 	sel = &sunxi_nand->sels[cs];
420*4882a593Smuzhiyun 	ctl |= NFC_CE_SEL(sel->cs) | NFC_EN | NFC_PAGE_SHIFT(nand->page_shift);
421*4882a593Smuzhiyun 	if (sel->rb >= 0)
422*4882a593Smuzhiyun 		ctl |= NFC_RB_SEL(sel->rb);
423*4882a593Smuzhiyun 
424*4882a593Smuzhiyun 	writel(mtd->writesize, nfc->regs + NFC_REG_SPARE_AREA);
425*4882a593Smuzhiyun 
426*4882a593Smuzhiyun 	if (nfc->clk_rate != sunxi_nand->clk_rate) {
427*4882a593Smuzhiyun 		clk_set_rate(nfc->mod_clk, sunxi_nand->clk_rate);
428*4882a593Smuzhiyun 		nfc->clk_rate = sunxi_nand->clk_rate;
429*4882a593Smuzhiyun 	}
430*4882a593Smuzhiyun 
431*4882a593Smuzhiyun 	writel(sunxi_nand->timing_ctl, nfc->regs + NFC_REG_TIMING_CTL);
432*4882a593Smuzhiyun 	writel(sunxi_nand->timing_cfg, nfc->regs + NFC_REG_TIMING_CFG);
433*4882a593Smuzhiyun 	writel(ctl, nfc->regs + NFC_REG_CTL);
434*4882a593Smuzhiyun }
435*4882a593Smuzhiyun 
sunxi_nfc_read_buf(struct nand_chip * nand,uint8_t * buf,int len)436*4882a593Smuzhiyun static void sunxi_nfc_read_buf(struct nand_chip *nand, uint8_t *buf, int len)
437*4882a593Smuzhiyun {
438*4882a593Smuzhiyun 	struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
439*4882a593Smuzhiyun 	struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
440*4882a593Smuzhiyun 	int ret;
441*4882a593Smuzhiyun 	int cnt;
442*4882a593Smuzhiyun 	int offs = 0;
443*4882a593Smuzhiyun 	u32 tmp;
444*4882a593Smuzhiyun 
445*4882a593Smuzhiyun 	while (len > offs) {
446*4882a593Smuzhiyun 		bool poll = false;
447*4882a593Smuzhiyun 
448*4882a593Smuzhiyun 		cnt = min(len - offs, NFC_SRAM_SIZE);
449*4882a593Smuzhiyun 
450*4882a593Smuzhiyun 		ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
451*4882a593Smuzhiyun 		if (ret)
452*4882a593Smuzhiyun 			break;
453*4882a593Smuzhiyun 
454*4882a593Smuzhiyun 		writel(cnt, nfc->regs + NFC_REG_CNT);
455*4882a593Smuzhiyun 		tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD;
456*4882a593Smuzhiyun 		writel(tmp, nfc->regs + NFC_REG_CMD);
457*4882a593Smuzhiyun 
458*4882a593Smuzhiyun 		/* Arbitrary limit for polling mode */
459*4882a593Smuzhiyun 		if (cnt < 64)
460*4882a593Smuzhiyun 			poll = true;
461*4882a593Smuzhiyun 
462*4882a593Smuzhiyun 		ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, poll, 0);
463*4882a593Smuzhiyun 		if (ret)
464*4882a593Smuzhiyun 			break;
465*4882a593Smuzhiyun 
466*4882a593Smuzhiyun 		if (buf)
467*4882a593Smuzhiyun 			memcpy_fromio(buf + offs, nfc->regs + NFC_RAM0_BASE,
468*4882a593Smuzhiyun 				      cnt);
469*4882a593Smuzhiyun 		offs += cnt;
470*4882a593Smuzhiyun 	}
471*4882a593Smuzhiyun }
472*4882a593Smuzhiyun 
sunxi_nfc_write_buf(struct nand_chip * nand,const uint8_t * buf,int len)473*4882a593Smuzhiyun static void sunxi_nfc_write_buf(struct nand_chip *nand, const uint8_t *buf,
474*4882a593Smuzhiyun 				int len)
475*4882a593Smuzhiyun {
476*4882a593Smuzhiyun 	struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
477*4882a593Smuzhiyun 	struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
478*4882a593Smuzhiyun 	int ret;
479*4882a593Smuzhiyun 	int cnt;
480*4882a593Smuzhiyun 	int offs = 0;
481*4882a593Smuzhiyun 	u32 tmp;
482*4882a593Smuzhiyun 
483*4882a593Smuzhiyun 	while (len > offs) {
484*4882a593Smuzhiyun 		bool poll = false;
485*4882a593Smuzhiyun 
486*4882a593Smuzhiyun 		cnt = min(len - offs, NFC_SRAM_SIZE);
487*4882a593Smuzhiyun 
488*4882a593Smuzhiyun 		ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
489*4882a593Smuzhiyun 		if (ret)
490*4882a593Smuzhiyun 			break;
491*4882a593Smuzhiyun 
492*4882a593Smuzhiyun 		writel(cnt, nfc->regs + NFC_REG_CNT);
493*4882a593Smuzhiyun 		memcpy_toio(nfc->regs + NFC_RAM0_BASE, buf + offs, cnt);
494*4882a593Smuzhiyun 		tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD |
495*4882a593Smuzhiyun 		      NFC_ACCESS_DIR;
496*4882a593Smuzhiyun 		writel(tmp, nfc->regs + NFC_REG_CMD);
497*4882a593Smuzhiyun 
498*4882a593Smuzhiyun 		/* Arbitrary limit for polling mode */
499*4882a593Smuzhiyun 		if (cnt < 64)
500*4882a593Smuzhiyun 			poll = true;
501*4882a593Smuzhiyun 
502*4882a593Smuzhiyun 		ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, poll, 0);
503*4882a593Smuzhiyun 		if (ret)
504*4882a593Smuzhiyun 			break;
505*4882a593Smuzhiyun 
506*4882a593Smuzhiyun 		offs += cnt;
507*4882a593Smuzhiyun 	}
508*4882a593Smuzhiyun }
509*4882a593Smuzhiyun 
510*4882a593Smuzhiyun /* These seed values have been extracted from Allwinner's BSP */
511*4882a593Smuzhiyun static const u16 sunxi_nfc_randomizer_page_seeds[] = {
512*4882a593Smuzhiyun 	0x2b75, 0x0bd0, 0x5ca3, 0x62d1, 0x1c93, 0x07e9, 0x2162, 0x3a72,
513*4882a593Smuzhiyun 	0x0d67, 0x67f9, 0x1be7, 0x077d, 0x032f, 0x0dac, 0x2716, 0x2436,
514*4882a593Smuzhiyun 	0x7922, 0x1510, 0x3860, 0x5287, 0x480f, 0x4252, 0x1789, 0x5a2d,
515*4882a593Smuzhiyun 	0x2a49, 0x5e10, 0x437f, 0x4b4e, 0x2f45, 0x216e, 0x5cb7, 0x7130,
516*4882a593Smuzhiyun 	0x2a3f, 0x60e4, 0x4dc9, 0x0ef0, 0x0f52, 0x1bb9, 0x6211, 0x7a56,
517*4882a593Smuzhiyun 	0x226d, 0x4ea7, 0x6f36, 0x3692, 0x38bf, 0x0c62, 0x05eb, 0x4c55,
518*4882a593Smuzhiyun 	0x60f4, 0x728c, 0x3b6f, 0x2037, 0x7f69, 0x0936, 0x651a, 0x4ceb,
519*4882a593Smuzhiyun 	0x6218, 0x79f3, 0x383f, 0x18d9, 0x4f05, 0x5c82, 0x2912, 0x6f17,
520*4882a593Smuzhiyun 	0x6856, 0x5938, 0x1007, 0x61ab, 0x3e7f, 0x57c2, 0x542f, 0x4f62,
521*4882a593Smuzhiyun 	0x7454, 0x2eac, 0x7739, 0x42d4, 0x2f90, 0x435a, 0x2e52, 0x2064,
522*4882a593Smuzhiyun 	0x637c, 0x66ad, 0x2c90, 0x0bad, 0x759c, 0x0029, 0x0986, 0x7126,
523*4882a593Smuzhiyun 	0x1ca7, 0x1605, 0x386a, 0x27f5, 0x1380, 0x6d75, 0x24c3, 0x0f8e,
524*4882a593Smuzhiyun 	0x2b7a, 0x1418, 0x1fd1, 0x7dc1, 0x2d8e, 0x43af, 0x2267, 0x7da3,
525*4882a593Smuzhiyun 	0x4e3d, 0x1338, 0x50db, 0x454d, 0x764d, 0x40a3, 0x42e6, 0x262b,
526*4882a593Smuzhiyun 	0x2d2e, 0x1aea, 0x2e17, 0x173d, 0x3a6e, 0x71bf, 0x25f9, 0x0a5d,
527*4882a593Smuzhiyun 	0x7c57, 0x0fbe, 0x46ce, 0x4939, 0x6b17, 0x37bb, 0x3e91, 0x76db,
528*4882a593Smuzhiyun };
529*4882a593Smuzhiyun 
530*4882a593Smuzhiyun /*
531*4882a593Smuzhiyun  * sunxi_nfc_randomizer_ecc512_seeds and sunxi_nfc_randomizer_ecc1024_seeds
532*4882a593Smuzhiyun  * have been generated using
533*4882a593Smuzhiyun  * sunxi_nfc_randomizer_step(seed, (step_size * 8) + 15), which is what
534*4882a593Smuzhiyun  * the randomizer engine does internally before de/scrambling OOB data.
535*4882a593Smuzhiyun  *
536*4882a593Smuzhiyun  * Those tables are statically defined to avoid calculating randomizer state
537*4882a593Smuzhiyun  * at runtime.
538*4882a593Smuzhiyun  */
539*4882a593Smuzhiyun static const u16 sunxi_nfc_randomizer_ecc512_seeds[] = {
540*4882a593Smuzhiyun 	0x3346, 0x367f, 0x1f18, 0x769a, 0x4f64, 0x068c, 0x2ef1, 0x6b64,
541*4882a593Smuzhiyun 	0x28a9, 0x15d7, 0x30f8, 0x3659, 0x53db, 0x7c5f, 0x71d4, 0x4409,
542*4882a593Smuzhiyun 	0x26eb, 0x03cc, 0x655d, 0x47d4, 0x4daa, 0x0877, 0x712d, 0x3617,
543*4882a593Smuzhiyun 	0x3264, 0x49aa, 0x7f9e, 0x588e, 0x4fbc, 0x7176, 0x7f91, 0x6c6d,
544*4882a593Smuzhiyun 	0x4b95, 0x5fb7, 0x3844, 0x4037, 0x0184, 0x081b, 0x0ee8, 0x5b91,
545*4882a593Smuzhiyun 	0x293d, 0x1f71, 0x0e6f, 0x402b, 0x5122, 0x1e52, 0x22be, 0x3d2d,
546*4882a593Smuzhiyun 	0x75bc, 0x7c60, 0x6291, 0x1a2f, 0x61d4, 0x74aa, 0x4140, 0x29ab,
547*4882a593Smuzhiyun 	0x472d, 0x2852, 0x017e, 0x15e8, 0x5ec2, 0x17cf, 0x7d0f, 0x06b8,
548*4882a593Smuzhiyun 	0x117a, 0x6b94, 0x789b, 0x3126, 0x6ac5, 0x5be7, 0x150f, 0x51f8,
549*4882a593Smuzhiyun 	0x7889, 0x0aa5, 0x663d, 0x77e8, 0x0b87, 0x3dcb, 0x360d, 0x218b,
550*4882a593Smuzhiyun 	0x512f, 0x7dc9, 0x6a4d, 0x630a, 0x3547, 0x1dd2, 0x5aea, 0x69a5,
551*4882a593Smuzhiyun 	0x7bfa, 0x5e4f, 0x1519, 0x6430, 0x3a0e, 0x5eb3, 0x5425, 0x0c7a,
552*4882a593Smuzhiyun 	0x5540, 0x3670, 0x63c1, 0x31e9, 0x5a39, 0x2de7, 0x5979, 0x2891,
553*4882a593Smuzhiyun 	0x1562, 0x014b, 0x5b05, 0x2756, 0x5a34, 0x13aa, 0x6cb5, 0x2c36,
554*4882a593Smuzhiyun 	0x5e72, 0x1306, 0x0861, 0x15ef, 0x1ee8, 0x5a37, 0x7ac4, 0x45dd,
555*4882a593Smuzhiyun 	0x44c4, 0x7266, 0x2f41, 0x3ccc, 0x045e, 0x7d40, 0x7c66, 0x0fa0,
556*4882a593Smuzhiyun };
557*4882a593Smuzhiyun 
558*4882a593Smuzhiyun static const u16 sunxi_nfc_randomizer_ecc1024_seeds[] = {
559*4882a593Smuzhiyun 	0x2cf5, 0x35f1, 0x63a4, 0x5274, 0x2bd2, 0x778b, 0x7285, 0x32b6,
560*4882a593Smuzhiyun 	0x6a5c, 0x70d6, 0x757d, 0x6769, 0x5375, 0x1e81, 0x0cf3, 0x3982,
561*4882a593Smuzhiyun 	0x6787, 0x042a, 0x6c49, 0x1925, 0x56a8, 0x40a9, 0x063e, 0x7bd9,
562*4882a593Smuzhiyun 	0x4dbf, 0x55ec, 0x672e, 0x7334, 0x5185, 0x4d00, 0x232a, 0x7e07,
563*4882a593Smuzhiyun 	0x445d, 0x6b92, 0x528f, 0x4255, 0x53ba, 0x7d82, 0x2a2e, 0x3a4e,
564*4882a593Smuzhiyun 	0x75eb, 0x450c, 0x6844, 0x1b5d, 0x581a, 0x4cc6, 0x0379, 0x37b2,
565*4882a593Smuzhiyun 	0x419f, 0x0e92, 0x6b27, 0x5624, 0x01e3, 0x07c1, 0x44a5, 0x130c,
566*4882a593Smuzhiyun 	0x13e8, 0x5910, 0x0876, 0x60c5, 0x54e3, 0x5b7f, 0x2269, 0x509f,
567*4882a593Smuzhiyun 	0x7665, 0x36fd, 0x3e9a, 0x0579, 0x6295, 0x14ef, 0x0a81, 0x1bcc,
568*4882a593Smuzhiyun 	0x4b16, 0x64db, 0x0514, 0x4f07, 0x0591, 0x3576, 0x6853, 0x0d9e,
569*4882a593Smuzhiyun 	0x259f, 0x38b7, 0x64fb, 0x3094, 0x4693, 0x6ddd, 0x29bb, 0x0bc8,
570*4882a593Smuzhiyun 	0x3f47, 0x490e, 0x0c0e, 0x7933, 0x3c9e, 0x5840, 0x398d, 0x3e68,
571*4882a593Smuzhiyun 	0x4af1, 0x71f5, 0x57cf, 0x1121, 0x64eb, 0x3579, 0x15ac, 0x584d,
572*4882a593Smuzhiyun 	0x5f2a, 0x47e2, 0x6528, 0x6eac, 0x196e, 0x6b96, 0x0450, 0x0179,
573*4882a593Smuzhiyun 	0x609c, 0x06e1, 0x4626, 0x42c7, 0x273e, 0x486f, 0x0705, 0x1601,
574*4882a593Smuzhiyun 	0x145b, 0x407e, 0x062b, 0x57a5, 0x53f9, 0x5659, 0x4410, 0x3ccd,
575*4882a593Smuzhiyun };
576*4882a593Smuzhiyun 
sunxi_nfc_randomizer_step(u16 state,int count)577*4882a593Smuzhiyun static u16 sunxi_nfc_randomizer_step(u16 state, int count)
578*4882a593Smuzhiyun {
579*4882a593Smuzhiyun 	state &= 0x7fff;
580*4882a593Smuzhiyun 
581*4882a593Smuzhiyun 	/*
582*4882a593Smuzhiyun 	 * This loop is just a simple implementation of a Fibonacci LFSR using
583*4882a593Smuzhiyun 	 * the x16 + x15 + 1 polynomial.
584*4882a593Smuzhiyun 	 */
585*4882a593Smuzhiyun 	while (count--)
586*4882a593Smuzhiyun 		state = ((state >> 1) |
587*4882a593Smuzhiyun 			 (((state ^ (state >> 1)) & 1) << 14)) & 0x7fff;
588*4882a593Smuzhiyun 
589*4882a593Smuzhiyun 	return state;
590*4882a593Smuzhiyun }
591*4882a593Smuzhiyun 
sunxi_nfc_randomizer_state(struct nand_chip * nand,int page,bool ecc)592*4882a593Smuzhiyun static u16 sunxi_nfc_randomizer_state(struct nand_chip *nand, int page,
593*4882a593Smuzhiyun 				      bool ecc)
594*4882a593Smuzhiyun {
595*4882a593Smuzhiyun 	struct mtd_info *mtd = nand_to_mtd(nand);
596*4882a593Smuzhiyun 	const u16 *seeds = sunxi_nfc_randomizer_page_seeds;
597*4882a593Smuzhiyun 	int mod = mtd_div_by_ws(mtd->erasesize, mtd);
598*4882a593Smuzhiyun 
599*4882a593Smuzhiyun 	if (mod > ARRAY_SIZE(sunxi_nfc_randomizer_page_seeds))
600*4882a593Smuzhiyun 		mod = ARRAY_SIZE(sunxi_nfc_randomizer_page_seeds);
601*4882a593Smuzhiyun 
602*4882a593Smuzhiyun 	if (ecc) {
603*4882a593Smuzhiyun 		if (mtd->ecc_step_size == 512)
604*4882a593Smuzhiyun 			seeds = sunxi_nfc_randomizer_ecc512_seeds;
605*4882a593Smuzhiyun 		else
606*4882a593Smuzhiyun 			seeds = sunxi_nfc_randomizer_ecc1024_seeds;
607*4882a593Smuzhiyun 	}
608*4882a593Smuzhiyun 
609*4882a593Smuzhiyun 	return seeds[page % mod];
610*4882a593Smuzhiyun }
611*4882a593Smuzhiyun 
sunxi_nfc_randomizer_config(struct nand_chip * nand,int page,bool ecc)612*4882a593Smuzhiyun static void sunxi_nfc_randomizer_config(struct nand_chip *nand, int page,
613*4882a593Smuzhiyun 					bool ecc)
614*4882a593Smuzhiyun {
615*4882a593Smuzhiyun 	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
616*4882a593Smuzhiyun 	u32 ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL);
617*4882a593Smuzhiyun 	u16 state;
618*4882a593Smuzhiyun 
619*4882a593Smuzhiyun 	if (!(nand->options & NAND_NEED_SCRAMBLING))
620*4882a593Smuzhiyun 		return;
621*4882a593Smuzhiyun 
622*4882a593Smuzhiyun 	ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL);
623*4882a593Smuzhiyun 	state = sunxi_nfc_randomizer_state(nand, page, ecc);
624*4882a593Smuzhiyun 	ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_RANDOM_SEED_MSK;
625*4882a593Smuzhiyun 	writel(ecc_ctl | NFC_RANDOM_SEED(state), nfc->regs + NFC_REG_ECC_CTL);
626*4882a593Smuzhiyun }
627*4882a593Smuzhiyun 
sunxi_nfc_randomizer_enable(struct nand_chip * nand)628*4882a593Smuzhiyun static void sunxi_nfc_randomizer_enable(struct nand_chip *nand)
629*4882a593Smuzhiyun {
630*4882a593Smuzhiyun 	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
631*4882a593Smuzhiyun 
632*4882a593Smuzhiyun 	if (!(nand->options & NAND_NEED_SCRAMBLING))
633*4882a593Smuzhiyun 		return;
634*4882a593Smuzhiyun 
635*4882a593Smuzhiyun 	writel(readl(nfc->regs + NFC_REG_ECC_CTL) | NFC_RANDOM_EN,
636*4882a593Smuzhiyun 	       nfc->regs + NFC_REG_ECC_CTL);
637*4882a593Smuzhiyun }
638*4882a593Smuzhiyun 
sunxi_nfc_randomizer_disable(struct nand_chip * nand)639*4882a593Smuzhiyun static void sunxi_nfc_randomizer_disable(struct nand_chip *nand)
640*4882a593Smuzhiyun {
641*4882a593Smuzhiyun 	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
642*4882a593Smuzhiyun 
643*4882a593Smuzhiyun 	if (!(nand->options & NAND_NEED_SCRAMBLING))
644*4882a593Smuzhiyun 		return;
645*4882a593Smuzhiyun 
646*4882a593Smuzhiyun 	writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_RANDOM_EN,
647*4882a593Smuzhiyun 	       nfc->regs + NFC_REG_ECC_CTL);
648*4882a593Smuzhiyun }
649*4882a593Smuzhiyun 
sunxi_nfc_randomize_bbm(struct nand_chip * nand,int page,u8 * bbm)650*4882a593Smuzhiyun static void sunxi_nfc_randomize_bbm(struct nand_chip *nand, int page, u8 *bbm)
651*4882a593Smuzhiyun {
652*4882a593Smuzhiyun 	u16 state = sunxi_nfc_randomizer_state(nand, page, true);
653*4882a593Smuzhiyun 
654*4882a593Smuzhiyun 	bbm[0] ^= state;
655*4882a593Smuzhiyun 	bbm[1] ^= sunxi_nfc_randomizer_step(state, 8);
656*4882a593Smuzhiyun }
657*4882a593Smuzhiyun 
sunxi_nfc_randomizer_write_buf(struct nand_chip * nand,const uint8_t * buf,int len,bool ecc,int page)658*4882a593Smuzhiyun static void sunxi_nfc_randomizer_write_buf(struct nand_chip *nand,
659*4882a593Smuzhiyun 					   const uint8_t *buf, int len,
660*4882a593Smuzhiyun 					   bool ecc, int page)
661*4882a593Smuzhiyun {
662*4882a593Smuzhiyun 	sunxi_nfc_randomizer_config(nand, page, ecc);
663*4882a593Smuzhiyun 	sunxi_nfc_randomizer_enable(nand);
664*4882a593Smuzhiyun 	sunxi_nfc_write_buf(nand, buf, len);
665*4882a593Smuzhiyun 	sunxi_nfc_randomizer_disable(nand);
666*4882a593Smuzhiyun }
667*4882a593Smuzhiyun 
sunxi_nfc_randomizer_read_buf(struct nand_chip * nand,uint8_t * buf,int len,bool ecc,int page)668*4882a593Smuzhiyun static void sunxi_nfc_randomizer_read_buf(struct nand_chip *nand, uint8_t *buf,
669*4882a593Smuzhiyun 					  int len, bool ecc, int page)
670*4882a593Smuzhiyun {
671*4882a593Smuzhiyun 	sunxi_nfc_randomizer_config(nand, page, ecc);
672*4882a593Smuzhiyun 	sunxi_nfc_randomizer_enable(nand);
673*4882a593Smuzhiyun 	sunxi_nfc_read_buf(nand, buf, len);
674*4882a593Smuzhiyun 	sunxi_nfc_randomizer_disable(nand);
675*4882a593Smuzhiyun }
676*4882a593Smuzhiyun 
sunxi_nfc_hw_ecc_enable(struct nand_chip * nand)677*4882a593Smuzhiyun static void sunxi_nfc_hw_ecc_enable(struct nand_chip *nand)
678*4882a593Smuzhiyun {
679*4882a593Smuzhiyun 	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
680*4882a593Smuzhiyun 	struct sunxi_nand_hw_ecc *data = nand->ecc.priv;
681*4882a593Smuzhiyun 	u32 ecc_ctl;
682*4882a593Smuzhiyun 
683*4882a593Smuzhiyun 	ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL);
684*4882a593Smuzhiyun 	ecc_ctl &= ~(NFC_ECC_MODE_MSK | NFC_ECC_PIPELINE |
685*4882a593Smuzhiyun 		     NFC_ECC_BLOCK_SIZE_MSK);
686*4882a593Smuzhiyun 	ecc_ctl |= NFC_ECC_EN | NFC_ECC_MODE(data->mode) | NFC_ECC_EXCEPTION |
687*4882a593Smuzhiyun 		   NFC_ECC_PIPELINE;
688*4882a593Smuzhiyun 
689*4882a593Smuzhiyun 	if (nand->ecc.size == 512)
690*4882a593Smuzhiyun 		ecc_ctl |= NFC_ECC_BLOCK_512;
691*4882a593Smuzhiyun 
692*4882a593Smuzhiyun 	writel(ecc_ctl, nfc->regs + NFC_REG_ECC_CTL);
693*4882a593Smuzhiyun }
694*4882a593Smuzhiyun 
sunxi_nfc_hw_ecc_disable(struct nand_chip * nand)695*4882a593Smuzhiyun static void sunxi_nfc_hw_ecc_disable(struct nand_chip *nand)
696*4882a593Smuzhiyun {
697*4882a593Smuzhiyun 	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
698*4882a593Smuzhiyun 
699*4882a593Smuzhiyun 	writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_ECC_EN,
700*4882a593Smuzhiyun 	       nfc->regs + NFC_REG_ECC_CTL);
701*4882a593Smuzhiyun }
702*4882a593Smuzhiyun 
sunxi_nfc_user_data_to_buf(u32 user_data,u8 * buf)703*4882a593Smuzhiyun static inline void sunxi_nfc_user_data_to_buf(u32 user_data, u8 *buf)
704*4882a593Smuzhiyun {
705*4882a593Smuzhiyun 	buf[0] = user_data;
706*4882a593Smuzhiyun 	buf[1] = user_data >> 8;
707*4882a593Smuzhiyun 	buf[2] = user_data >> 16;
708*4882a593Smuzhiyun 	buf[3] = user_data >> 24;
709*4882a593Smuzhiyun }
710*4882a593Smuzhiyun 
sunxi_nfc_buf_to_user_data(const u8 * buf)711*4882a593Smuzhiyun static inline u32 sunxi_nfc_buf_to_user_data(const u8 *buf)
712*4882a593Smuzhiyun {
713*4882a593Smuzhiyun 	return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
714*4882a593Smuzhiyun }
715*4882a593Smuzhiyun 
sunxi_nfc_hw_ecc_get_prot_oob_bytes(struct nand_chip * nand,u8 * oob,int step,bool bbm,int page)716*4882a593Smuzhiyun static void sunxi_nfc_hw_ecc_get_prot_oob_bytes(struct nand_chip *nand, u8 *oob,
717*4882a593Smuzhiyun 						int step, bool bbm, int page)
718*4882a593Smuzhiyun {
719*4882a593Smuzhiyun 	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
720*4882a593Smuzhiyun 
721*4882a593Smuzhiyun 	sunxi_nfc_user_data_to_buf(readl(nfc->regs + NFC_REG_USER_DATA(step)),
722*4882a593Smuzhiyun 				   oob);
723*4882a593Smuzhiyun 
724*4882a593Smuzhiyun 	/* De-randomize the Bad Block Marker. */
725*4882a593Smuzhiyun 	if (bbm && (nand->options & NAND_NEED_SCRAMBLING))
726*4882a593Smuzhiyun 		sunxi_nfc_randomize_bbm(nand, page, oob);
727*4882a593Smuzhiyun }
728*4882a593Smuzhiyun 
sunxi_nfc_hw_ecc_set_prot_oob_bytes(struct nand_chip * nand,const u8 * oob,int step,bool bbm,int page)729*4882a593Smuzhiyun static void sunxi_nfc_hw_ecc_set_prot_oob_bytes(struct nand_chip *nand,
730*4882a593Smuzhiyun 						const u8 *oob, int step,
731*4882a593Smuzhiyun 						bool bbm, int page)
732*4882a593Smuzhiyun {
733*4882a593Smuzhiyun 	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
734*4882a593Smuzhiyun 	u8 user_data[4];
735*4882a593Smuzhiyun 
736*4882a593Smuzhiyun 	/* Randomize the Bad Block Marker. */
737*4882a593Smuzhiyun 	if (bbm && (nand->options & NAND_NEED_SCRAMBLING)) {
738*4882a593Smuzhiyun 		memcpy(user_data, oob, sizeof(user_data));
739*4882a593Smuzhiyun 		sunxi_nfc_randomize_bbm(nand, page, user_data);
740*4882a593Smuzhiyun 		oob = user_data;
741*4882a593Smuzhiyun 	}
742*4882a593Smuzhiyun 
743*4882a593Smuzhiyun 	writel(sunxi_nfc_buf_to_user_data(oob),
744*4882a593Smuzhiyun 	       nfc->regs + NFC_REG_USER_DATA(step));
745*4882a593Smuzhiyun }
746*4882a593Smuzhiyun 
sunxi_nfc_hw_ecc_update_stats(struct nand_chip * nand,unsigned int * max_bitflips,int ret)747*4882a593Smuzhiyun static void sunxi_nfc_hw_ecc_update_stats(struct nand_chip *nand,
748*4882a593Smuzhiyun 					  unsigned int *max_bitflips, int ret)
749*4882a593Smuzhiyun {
750*4882a593Smuzhiyun 	struct mtd_info *mtd = nand_to_mtd(nand);
751*4882a593Smuzhiyun 
752*4882a593Smuzhiyun 	if (ret < 0) {
753*4882a593Smuzhiyun 		mtd->ecc_stats.failed++;
754*4882a593Smuzhiyun 	} else {
755*4882a593Smuzhiyun 		mtd->ecc_stats.corrected += ret;
756*4882a593Smuzhiyun 		*max_bitflips = max_t(unsigned int, *max_bitflips, ret);
757*4882a593Smuzhiyun 	}
758*4882a593Smuzhiyun }
759*4882a593Smuzhiyun 
sunxi_nfc_hw_ecc_correct(struct nand_chip * nand,u8 * data,u8 * oob,int step,u32 status,bool * erased)760*4882a593Smuzhiyun static int sunxi_nfc_hw_ecc_correct(struct nand_chip *nand, u8 *data, u8 *oob,
761*4882a593Smuzhiyun 				    int step, u32 status, bool *erased)
762*4882a593Smuzhiyun {
763*4882a593Smuzhiyun 	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
764*4882a593Smuzhiyun 	struct nand_ecc_ctrl *ecc = &nand->ecc;
765*4882a593Smuzhiyun 	u32 tmp;
766*4882a593Smuzhiyun 
767*4882a593Smuzhiyun 	*erased = false;
768*4882a593Smuzhiyun 
769*4882a593Smuzhiyun 	if (status & NFC_ECC_ERR(step))
770*4882a593Smuzhiyun 		return -EBADMSG;
771*4882a593Smuzhiyun 
772*4882a593Smuzhiyun 	if (status & NFC_ECC_PAT_FOUND(step)) {
773*4882a593Smuzhiyun 		u8 pattern;
774*4882a593Smuzhiyun 
775*4882a593Smuzhiyun 		if (unlikely(!(readl(nfc->regs + NFC_REG_PAT_ID) & 0x1))) {
776*4882a593Smuzhiyun 			pattern = 0x0;
777*4882a593Smuzhiyun 		} else {
778*4882a593Smuzhiyun 			pattern = 0xff;
779*4882a593Smuzhiyun 			*erased = true;
780*4882a593Smuzhiyun 		}
781*4882a593Smuzhiyun 
782*4882a593Smuzhiyun 		if (data)
783*4882a593Smuzhiyun 			memset(data, pattern, ecc->size);
784*4882a593Smuzhiyun 
785*4882a593Smuzhiyun 		if (oob)
786*4882a593Smuzhiyun 			memset(oob, pattern, ecc->bytes + 4);
787*4882a593Smuzhiyun 
788*4882a593Smuzhiyun 		return 0;
789*4882a593Smuzhiyun 	}
790*4882a593Smuzhiyun 
791*4882a593Smuzhiyun 	tmp = readl(nfc->regs + NFC_REG_ECC_ERR_CNT(step));
792*4882a593Smuzhiyun 
793*4882a593Smuzhiyun 	return NFC_ECC_ERR_CNT(step, tmp);
794*4882a593Smuzhiyun }
795*4882a593Smuzhiyun 
sunxi_nfc_hw_ecc_read_chunk(struct nand_chip * nand,u8 * data,int data_off,u8 * oob,int oob_off,int * cur_off,unsigned int * max_bitflips,bool bbm,bool oob_required,int page)796*4882a593Smuzhiyun static int sunxi_nfc_hw_ecc_read_chunk(struct nand_chip *nand,
797*4882a593Smuzhiyun 				       u8 *data, int data_off,
798*4882a593Smuzhiyun 				       u8 *oob, int oob_off,
799*4882a593Smuzhiyun 				       int *cur_off,
800*4882a593Smuzhiyun 				       unsigned int *max_bitflips,
801*4882a593Smuzhiyun 				       bool bbm, bool oob_required, int page)
802*4882a593Smuzhiyun {
803*4882a593Smuzhiyun 	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
804*4882a593Smuzhiyun 	struct nand_ecc_ctrl *ecc = &nand->ecc;
805*4882a593Smuzhiyun 	int raw_mode = 0;
806*4882a593Smuzhiyun 	bool erased;
807*4882a593Smuzhiyun 	int ret;
808*4882a593Smuzhiyun 
809*4882a593Smuzhiyun 	if (*cur_off != data_off)
810*4882a593Smuzhiyun 		nand_change_read_column_op(nand, data_off, NULL, 0, false);
811*4882a593Smuzhiyun 
812*4882a593Smuzhiyun 	sunxi_nfc_randomizer_read_buf(nand, NULL, ecc->size, false, page);
813*4882a593Smuzhiyun 
814*4882a593Smuzhiyun 	if (data_off + ecc->size != oob_off)
815*4882a593Smuzhiyun 		nand_change_read_column_op(nand, oob_off, NULL, 0, false);
816*4882a593Smuzhiyun 
817*4882a593Smuzhiyun 	ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
818*4882a593Smuzhiyun 	if (ret)
819*4882a593Smuzhiyun 		return ret;
820*4882a593Smuzhiyun 
821*4882a593Smuzhiyun 	sunxi_nfc_randomizer_enable(nand);
822*4882a593Smuzhiyun 	writel(NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | NFC_ECC_OP,
823*4882a593Smuzhiyun 	       nfc->regs + NFC_REG_CMD);
824*4882a593Smuzhiyun 
825*4882a593Smuzhiyun 	ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, false, 0);
826*4882a593Smuzhiyun 	sunxi_nfc_randomizer_disable(nand);
827*4882a593Smuzhiyun 	if (ret)
828*4882a593Smuzhiyun 		return ret;
829*4882a593Smuzhiyun 
830*4882a593Smuzhiyun 	*cur_off = oob_off + ecc->bytes + 4;
831*4882a593Smuzhiyun 
832*4882a593Smuzhiyun 	ret = sunxi_nfc_hw_ecc_correct(nand, data, oob_required ? oob : NULL, 0,
833*4882a593Smuzhiyun 				       readl(nfc->regs + NFC_REG_ECC_ST),
834*4882a593Smuzhiyun 				       &erased);
835*4882a593Smuzhiyun 	if (erased)
836*4882a593Smuzhiyun 		return 1;
837*4882a593Smuzhiyun 
838*4882a593Smuzhiyun 	if (ret < 0) {
839*4882a593Smuzhiyun 		/*
840*4882a593Smuzhiyun 		 * Re-read the data with the randomizer disabled to identify
841*4882a593Smuzhiyun 		 * bitflips in erased pages.
842*4882a593Smuzhiyun 		 */
843*4882a593Smuzhiyun 		if (nand->options & NAND_NEED_SCRAMBLING)
844*4882a593Smuzhiyun 			nand_change_read_column_op(nand, data_off, data,
845*4882a593Smuzhiyun 						   ecc->size, false);
846*4882a593Smuzhiyun 		else
847*4882a593Smuzhiyun 			memcpy_fromio(data, nfc->regs + NFC_RAM0_BASE,
848*4882a593Smuzhiyun 				      ecc->size);
849*4882a593Smuzhiyun 
850*4882a593Smuzhiyun 		nand_change_read_column_op(nand, oob_off, oob, ecc->bytes + 4,
851*4882a593Smuzhiyun 					   false);
852*4882a593Smuzhiyun 
853*4882a593Smuzhiyun 		ret = nand_check_erased_ecc_chunk(data,	ecc->size,
854*4882a593Smuzhiyun 						  oob, ecc->bytes + 4,
855*4882a593Smuzhiyun 						  NULL, 0, ecc->strength);
856*4882a593Smuzhiyun 		if (ret >= 0)
857*4882a593Smuzhiyun 			raw_mode = 1;
858*4882a593Smuzhiyun 	} else {
859*4882a593Smuzhiyun 		memcpy_fromio(data, nfc->regs + NFC_RAM0_BASE, ecc->size);
860*4882a593Smuzhiyun 
861*4882a593Smuzhiyun 		if (oob_required) {
862*4882a593Smuzhiyun 			nand_change_read_column_op(nand, oob_off, NULL, 0,
863*4882a593Smuzhiyun 						   false);
864*4882a593Smuzhiyun 			sunxi_nfc_randomizer_read_buf(nand, oob, ecc->bytes + 4,
865*4882a593Smuzhiyun 						      true, page);
866*4882a593Smuzhiyun 
867*4882a593Smuzhiyun 			sunxi_nfc_hw_ecc_get_prot_oob_bytes(nand, oob, 0,
868*4882a593Smuzhiyun 							    bbm, page);
869*4882a593Smuzhiyun 		}
870*4882a593Smuzhiyun 	}
871*4882a593Smuzhiyun 
872*4882a593Smuzhiyun 	sunxi_nfc_hw_ecc_update_stats(nand, max_bitflips, ret);
873*4882a593Smuzhiyun 
874*4882a593Smuzhiyun 	return raw_mode;
875*4882a593Smuzhiyun }
876*4882a593Smuzhiyun 
sunxi_nfc_hw_ecc_read_extra_oob(struct nand_chip * nand,u8 * oob,int * cur_off,bool randomize,int page)877*4882a593Smuzhiyun static void sunxi_nfc_hw_ecc_read_extra_oob(struct nand_chip *nand,
878*4882a593Smuzhiyun 					    u8 *oob, int *cur_off,
879*4882a593Smuzhiyun 					    bool randomize, int page)
880*4882a593Smuzhiyun {
881*4882a593Smuzhiyun 	struct mtd_info *mtd = nand_to_mtd(nand);
882*4882a593Smuzhiyun 	struct nand_ecc_ctrl *ecc = &nand->ecc;
883*4882a593Smuzhiyun 	int offset = ((ecc->bytes + 4) * ecc->steps);
884*4882a593Smuzhiyun 	int len = mtd->oobsize - offset;
885*4882a593Smuzhiyun 
886*4882a593Smuzhiyun 	if (len <= 0)
887*4882a593Smuzhiyun 		return;
888*4882a593Smuzhiyun 
889*4882a593Smuzhiyun 	if (!cur_off || *cur_off != offset)
890*4882a593Smuzhiyun 		nand_change_read_column_op(nand, mtd->writesize, NULL, 0,
891*4882a593Smuzhiyun 					   false);
892*4882a593Smuzhiyun 
893*4882a593Smuzhiyun 	if (!randomize)
894*4882a593Smuzhiyun 		sunxi_nfc_read_buf(nand, oob + offset, len);
895*4882a593Smuzhiyun 	else
896*4882a593Smuzhiyun 		sunxi_nfc_randomizer_read_buf(nand, oob + offset, len,
897*4882a593Smuzhiyun 					      false, page);
898*4882a593Smuzhiyun 
899*4882a593Smuzhiyun 	if (cur_off)
900*4882a593Smuzhiyun 		*cur_off = mtd->oobsize + mtd->writesize;
901*4882a593Smuzhiyun }
902*4882a593Smuzhiyun 
sunxi_nfc_hw_ecc_read_chunks_dma(struct nand_chip * nand,uint8_t * buf,int oob_required,int page,int nchunks)903*4882a593Smuzhiyun static int sunxi_nfc_hw_ecc_read_chunks_dma(struct nand_chip *nand, uint8_t *buf,
904*4882a593Smuzhiyun 					    int oob_required, int page,
905*4882a593Smuzhiyun 					    int nchunks)
906*4882a593Smuzhiyun {
907*4882a593Smuzhiyun 	bool randomized = nand->options & NAND_NEED_SCRAMBLING;
908*4882a593Smuzhiyun 	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
909*4882a593Smuzhiyun 	struct mtd_info *mtd = nand_to_mtd(nand);
910*4882a593Smuzhiyun 	struct nand_ecc_ctrl *ecc = &nand->ecc;
911*4882a593Smuzhiyun 	unsigned int max_bitflips = 0;
912*4882a593Smuzhiyun 	int ret, i, raw_mode = 0;
913*4882a593Smuzhiyun 	struct scatterlist sg;
914*4882a593Smuzhiyun 	u32 status;
915*4882a593Smuzhiyun 
916*4882a593Smuzhiyun 	ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
917*4882a593Smuzhiyun 	if (ret)
918*4882a593Smuzhiyun 		return ret;
919*4882a593Smuzhiyun 
920*4882a593Smuzhiyun 	ret = sunxi_nfc_dma_op_prepare(nfc, buf, ecc->size, nchunks,
921*4882a593Smuzhiyun 				       DMA_FROM_DEVICE, &sg);
922*4882a593Smuzhiyun 	if (ret)
923*4882a593Smuzhiyun 		return ret;
924*4882a593Smuzhiyun 
925*4882a593Smuzhiyun 	sunxi_nfc_hw_ecc_enable(nand);
926*4882a593Smuzhiyun 	sunxi_nfc_randomizer_config(nand, page, false);
927*4882a593Smuzhiyun 	sunxi_nfc_randomizer_enable(nand);
928*4882a593Smuzhiyun 
929*4882a593Smuzhiyun 	writel((NAND_CMD_RNDOUTSTART << 16) | (NAND_CMD_RNDOUT << 8) |
930*4882a593Smuzhiyun 	       NAND_CMD_READSTART, nfc->regs + NFC_REG_RCMD_SET);
931*4882a593Smuzhiyun 
932*4882a593Smuzhiyun 	dma_async_issue_pending(nfc->dmac);
933*4882a593Smuzhiyun 
934*4882a593Smuzhiyun 	writel(NFC_PAGE_OP | NFC_DATA_SWAP_METHOD | NFC_DATA_TRANS,
935*4882a593Smuzhiyun 	       nfc->regs + NFC_REG_CMD);
936*4882a593Smuzhiyun 
937*4882a593Smuzhiyun 	ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, false, 0);
938*4882a593Smuzhiyun 	if (ret)
939*4882a593Smuzhiyun 		dmaengine_terminate_all(nfc->dmac);
940*4882a593Smuzhiyun 
941*4882a593Smuzhiyun 	sunxi_nfc_randomizer_disable(nand);
942*4882a593Smuzhiyun 	sunxi_nfc_hw_ecc_disable(nand);
943*4882a593Smuzhiyun 
944*4882a593Smuzhiyun 	sunxi_nfc_dma_op_cleanup(nfc, DMA_FROM_DEVICE, &sg);
945*4882a593Smuzhiyun 
946*4882a593Smuzhiyun 	if (ret)
947*4882a593Smuzhiyun 		return ret;
948*4882a593Smuzhiyun 
949*4882a593Smuzhiyun 	status = readl(nfc->regs + NFC_REG_ECC_ST);
950*4882a593Smuzhiyun 
951*4882a593Smuzhiyun 	for (i = 0; i < nchunks; i++) {
952*4882a593Smuzhiyun 		int data_off = i * ecc->size;
953*4882a593Smuzhiyun 		int oob_off = i * (ecc->bytes + 4);
954*4882a593Smuzhiyun 		u8 *data = buf + data_off;
955*4882a593Smuzhiyun 		u8 *oob = nand->oob_poi + oob_off;
956*4882a593Smuzhiyun 		bool erased;
957*4882a593Smuzhiyun 
958*4882a593Smuzhiyun 		ret = sunxi_nfc_hw_ecc_correct(nand, randomized ? data : NULL,
959*4882a593Smuzhiyun 					       oob_required ? oob : NULL,
960*4882a593Smuzhiyun 					       i, status, &erased);
961*4882a593Smuzhiyun 
962*4882a593Smuzhiyun 		/* ECC errors are handled in the second loop. */
963*4882a593Smuzhiyun 		if (ret < 0)
964*4882a593Smuzhiyun 			continue;
965*4882a593Smuzhiyun 
966*4882a593Smuzhiyun 		if (oob_required && !erased) {
967*4882a593Smuzhiyun 			/* TODO: use DMA to retrieve OOB */
968*4882a593Smuzhiyun 			nand_change_read_column_op(nand,
969*4882a593Smuzhiyun 						   mtd->writesize + oob_off,
970*4882a593Smuzhiyun 						   oob, ecc->bytes + 4, false);
971*4882a593Smuzhiyun 
972*4882a593Smuzhiyun 			sunxi_nfc_hw_ecc_get_prot_oob_bytes(nand, oob, i,
973*4882a593Smuzhiyun 							    !i, page);
974*4882a593Smuzhiyun 		}
975*4882a593Smuzhiyun 
976*4882a593Smuzhiyun 		if (erased)
977*4882a593Smuzhiyun 			raw_mode = 1;
978*4882a593Smuzhiyun 
979*4882a593Smuzhiyun 		sunxi_nfc_hw_ecc_update_stats(nand, &max_bitflips, ret);
980*4882a593Smuzhiyun 	}
981*4882a593Smuzhiyun 
982*4882a593Smuzhiyun 	if (status & NFC_ECC_ERR_MSK) {
983*4882a593Smuzhiyun 		for (i = 0; i < nchunks; i++) {
984*4882a593Smuzhiyun 			int data_off = i * ecc->size;
985*4882a593Smuzhiyun 			int oob_off = i * (ecc->bytes + 4);
986*4882a593Smuzhiyun 			u8 *data = buf + data_off;
987*4882a593Smuzhiyun 			u8 *oob = nand->oob_poi + oob_off;
988*4882a593Smuzhiyun 
989*4882a593Smuzhiyun 			if (!(status & NFC_ECC_ERR(i)))
990*4882a593Smuzhiyun 				continue;
991*4882a593Smuzhiyun 
992*4882a593Smuzhiyun 			/*
993*4882a593Smuzhiyun 			 * Re-read the data with the randomizer disabled to
994*4882a593Smuzhiyun 			 * identify bitflips in erased pages.
995*4882a593Smuzhiyun 			 * TODO: use DMA to read page in raw mode
996*4882a593Smuzhiyun 			 */
997*4882a593Smuzhiyun 			if (randomized)
998*4882a593Smuzhiyun 				nand_change_read_column_op(nand, data_off,
999*4882a593Smuzhiyun 							   data, ecc->size,
1000*4882a593Smuzhiyun 							   false);
1001*4882a593Smuzhiyun 
1002*4882a593Smuzhiyun 			/* TODO: use DMA to retrieve OOB */
1003*4882a593Smuzhiyun 			nand_change_read_column_op(nand,
1004*4882a593Smuzhiyun 						   mtd->writesize + oob_off,
1005*4882a593Smuzhiyun 						   oob, ecc->bytes + 4, false);
1006*4882a593Smuzhiyun 
1007*4882a593Smuzhiyun 			ret = nand_check_erased_ecc_chunk(data,	ecc->size,
1008*4882a593Smuzhiyun 							  oob, ecc->bytes + 4,
1009*4882a593Smuzhiyun 							  NULL, 0,
1010*4882a593Smuzhiyun 							  ecc->strength);
1011*4882a593Smuzhiyun 			if (ret >= 0)
1012*4882a593Smuzhiyun 				raw_mode = 1;
1013*4882a593Smuzhiyun 
1014*4882a593Smuzhiyun 			sunxi_nfc_hw_ecc_update_stats(nand, &max_bitflips, ret);
1015*4882a593Smuzhiyun 		}
1016*4882a593Smuzhiyun 	}
1017*4882a593Smuzhiyun 
1018*4882a593Smuzhiyun 	if (oob_required)
1019*4882a593Smuzhiyun 		sunxi_nfc_hw_ecc_read_extra_oob(nand, nand->oob_poi,
1020*4882a593Smuzhiyun 						NULL, !raw_mode,
1021*4882a593Smuzhiyun 						page);
1022*4882a593Smuzhiyun 
1023*4882a593Smuzhiyun 	return max_bitflips;
1024*4882a593Smuzhiyun }
1025*4882a593Smuzhiyun 
sunxi_nfc_hw_ecc_write_chunk(struct nand_chip * nand,const u8 * data,int data_off,const u8 * oob,int oob_off,int * cur_off,bool bbm,int page)1026*4882a593Smuzhiyun static int sunxi_nfc_hw_ecc_write_chunk(struct nand_chip *nand,
1027*4882a593Smuzhiyun 					const u8 *data, int data_off,
1028*4882a593Smuzhiyun 					const u8 *oob, int oob_off,
1029*4882a593Smuzhiyun 					int *cur_off, bool bbm,
1030*4882a593Smuzhiyun 					int page)
1031*4882a593Smuzhiyun {
1032*4882a593Smuzhiyun 	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
1033*4882a593Smuzhiyun 	struct nand_ecc_ctrl *ecc = &nand->ecc;
1034*4882a593Smuzhiyun 	int ret;
1035*4882a593Smuzhiyun 
1036*4882a593Smuzhiyun 	if (data_off != *cur_off)
1037*4882a593Smuzhiyun 		nand_change_write_column_op(nand, data_off, NULL, 0, false);
1038*4882a593Smuzhiyun 
1039*4882a593Smuzhiyun 	sunxi_nfc_randomizer_write_buf(nand, data, ecc->size, false, page);
1040*4882a593Smuzhiyun 
1041*4882a593Smuzhiyun 	if (data_off + ecc->size != oob_off)
1042*4882a593Smuzhiyun 		nand_change_write_column_op(nand, oob_off, NULL, 0, false);
1043*4882a593Smuzhiyun 
1044*4882a593Smuzhiyun 	ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
1045*4882a593Smuzhiyun 	if (ret)
1046*4882a593Smuzhiyun 		return ret;
1047*4882a593Smuzhiyun 
1048*4882a593Smuzhiyun 	sunxi_nfc_randomizer_enable(nand);
1049*4882a593Smuzhiyun 	sunxi_nfc_hw_ecc_set_prot_oob_bytes(nand, oob, 0, bbm, page);
1050*4882a593Smuzhiyun 
1051*4882a593Smuzhiyun 	writel(NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD |
1052*4882a593Smuzhiyun 	       NFC_ACCESS_DIR | NFC_ECC_OP,
1053*4882a593Smuzhiyun 	       nfc->regs + NFC_REG_CMD);
1054*4882a593Smuzhiyun 
1055*4882a593Smuzhiyun 	ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, false, 0);
1056*4882a593Smuzhiyun 	sunxi_nfc_randomizer_disable(nand);
1057*4882a593Smuzhiyun 	if (ret)
1058*4882a593Smuzhiyun 		return ret;
1059*4882a593Smuzhiyun 
1060*4882a593Smuzhiyun 	*cur_off = oob_off + ecc->bytes + 4;
1061*4882a593Smuzhiyun 
1062*4882a593Smuzhiyun 	return 0;
1063*4882a593Smuzhiyun }
1064*4882a593Smuzhiyun 
sunxi_nfc_hw_ecc_write_extra_oob(struct nand_chip * nand,u8 * oob,int * cur_off,int page)1065*4882a593Smuzhiyun static void sunxi_nfc_hw_ecc_write_extra_oob(struct nand_chip *nand,
1066*4882a593Smuzhiyun 					     u8 *oob, int *cur_off,
1067*4882a593Smuzhiyun 					     int page)
1068*4882a593Smuzhiyun {
1069*4882a593Smuzhiyun 	struct mtd_info *mtd = nand_to_mtd(nand);
1070*4882a593Smuzhiyun 	struct nand_ecc_ctrl *ecc = &nand->ecc;
1071*4882a593Smuzhiyun 	int offset = ((ecc->bytes + 4) * ecc->steps);
1072*4882a593Smuzhiyun 	int len = mtd->oobsize - offset;
1073*4882a593Smuzhiyun 
1074*4882a593Smuzhiyun 	if (len <= 0)
1075*4882a593Smuzhiyun 		return;
1076*4882a593Smuzhiyun 
1077*4882a593Smuzhiyun 	if (!cur_off || *cur_off != offset)
1078*4882a593Smuzhiyun 		nand_change_write_column_op(nand, offset + mtd->writesize,
1079*4882a593Smuzhiyun 					    NULL, 0, false);
1080*4882a593Smuzhiyun 
1081*4882a593Smuzhiyun 	sunxi_nfc_randomizer_write_buf(nand, oob + offset, len, false, page);
1082*4882a593Smuzhiyun 
1083*4882a593Smuzhiyun 	if (cur_off)
1084*4882a593Smuzhiyun 		*cur_off = mtd->oobsize + mtd->writesize;
1085*4882a593Smuzhiyun }
1086*4882a593Smuzhiyun 
sunxi_nfc_hw_ecc_read_page(struct nand_chip * nand,uint8_t * buf,int oob_required,int page)1087*4882a593Smuzhiyun static int sunxi_nfc_hw_ecc_read_page(struct nand_chip *nand, uint8_t *buf,
1088*4882a593Smuzhiyun 				      int oob_required, int page)
1089*4882a593Smuzhiyun {
1090*4882a593Smuzhiyun 	struct mtd_info *mtd = nand_to_mtd(nand);
1091*4882a593Smuzhiyun 	struct nand_ecc_ctrl *ecc = &nand->ecc;
1092*4882a593Smuzhiyun 	unsigned int max_bitflips = 0;
1093*4882a593Smuzhiyun 	int ret, i, cur_off = 0;
1094*4882a593Smuzhiyun 	bool raw_mode = false;
1095*4882a593Smuzhiyun 
1096*4882a593Smuzhiyun 	sunxi_nfc_select_chip(nand, nand->cur_cs);
1097*4882a593Smuzhiyun 
1098*4882a593Smuzhiyun 	nand_read_page_op(nand, page, 0, NULL, 0);
1099*4882a593Smuzhiyun 
1100*4882a593Smuzhiyun 	sunxi_nfc_hw_ecc_enable(nand);
1101*4882a593Smuzhiyun 
1102*4882a593Smuzhiyun 	for (i = 0; i < ecc->steps; i++) {
1103*4882a593Smuzhiyun 		int data_off = i * ecc->size;
1104*4882a593Smuzhiyun 		int oob_off = i * (ecc->bytes + 4);
1105*4882a593Smuzhiyun 		u8 *data = buf + data_off;
1106*4882a593Smuzhiyun 		u8 *oob = nand->oob_poi + oob_off;
1107*4882a593Smuzhiyun 
1108*4882a593Smuzhiyun 		ret = sunxi_nfc_hw_ecc_read_chunk(nand, data, data_off, oob,
1109*4882a593Smuzhiyun 						  oob_off + mtd->writesize,
1110*4882a593Smuzhiyun 						  &cur_off, &max_bitflips,
1111*4882a593Smuzhiyun 						  !i, oob_required, page);
1112*4882a593Smuzhiyun 		if (ret < 0)
1113*4882a593Smuzhiyun 			return ret;
1114*4882a593Smuzhiyun 		else if (ret)
1115*4882a593Smuzhiyun 			raw_mode = true;
1116*4882a593Smuzhiyun 	}
1117*4882a593Smuzhiyun 
1118*4882a593Smuzhiyun 	if (oob_required)
1119*4882a593Smuzhiyun 		sunxi_nfc_hw_ecc_read_extra_oob(nand, nand->oob_poi, &cur_off,
1120*4882a593Smuzhiyun 						!raw_mode, page);
1121*4882a593Smuzhiyun 
1122*4882a593Smuzhiyun 	sunxi_nfc_hw_ecc_disable(nand);
1123*4882a593Smuzhiyun 
1124*4882a593Smuzhiyun 	return max_bitflips;
1125*4882a593Smuzhiyun }
1126*4882a593Smuzhiyun 
sunxi_nfc_hw_ecc_read_page_dma(struct nand_chip * nand,u8 * buf,int oob_required,int page)1127*4882a593Smuzhiyun static int sunxi_nfc_hw_ecc_read_page_dma(struct nand_chip *nand, u8 *buf,
1128*4882a593Smuzhiyun 					  int oob_required, int page)
1129*4882a593Smuzhiyun {
1130*4882a593Smuzhiyun 	int ret;
1131*4882a593Smuzhiyun 
1132*4882a593Smuzhiyun 	sunxi_nfc_select_chip(nand, nand->cur_cs);
1133*4882a593Smuzhiyun 
1134*4882a593Smuzhiyun 	nand_read_page_op(nand, page, 0, NULL, 0);
1135*4882a593Smuzhiyun 
1136*4882a593Smuzhiyun 	ret = sunxi_nfc_hw_ecc_read_chunks_dma(nand, buf, oob_required, page,
1137*4882a593Smuzhiyun 					       nand->ecc.steps);
1138*4882a593Smuzhiyun 	if (ret >= 0)
1139*4882a593Smuzhiyun 		return ret;
1140*4882a593Smuzhiyun 
1141*4882a593Smuzhiyun 	/* Fallback to PIO mode */
1142*4882a593Smuzhiyun 	return sunxi_nfc_hw_ecc_read_page(nand, buf, oob_required, page);
1143*4882a593Smuzhiyun }
1144*4882a593Smuzhiyun 
sunxi_nfc_hw_ecc_read_subpage(struct nand_chip * nand,u32 data_offs,u32 readlen,u8 * bufpoi,int page)1145*4882a593Smuzhiyun static int sunxi_nfc_hw_ecc_read_subpage(struct nand_chip *nand,
1146*4882a593Smuzhiyun 					 u32 data_offs, u32 readlen,
1147*4882a593Smuzhiyun 					 u8 *bufpoi, int page)
1148*4882a593Smuzhiyun {
1149*4882a593Smuzhiyun 	struct mtd_info *mtd = nand_to_mtd(nand);
1150*4882a593Smuzhiyun 	struct nand_ecc_ctrl *ecc = &nand->ecc;
1151*4882a593Smuzhiyun 	int ret, i, cur_off = 0;
1152*4882a593Smuzhiyun 	unsigned int max_bitflips = 0;
1153*4882a593Smuzhiyun 
1154*4882a593Smuzhiyun 	sunxi_nfc_select_chip(nand, nand->cur_cs);
1155*4882a593Smuzhiyun 
1156*4882a593Smuzhiyun 	nand_read_page_op(nand, page, 0, NULL, 0);
1157*4882a593Smuzhiyun 
1158*4882a593Smuzhiyun 	sunxi_nfc_hw_ecc_enable(nand);
1159*4882a593Smuzhiyun 
1160*4882a593Smuzhiyun 	for (i = data_offs / ecc->size;
1161*4882a593Smuzhiyun 	     i < DIV_ROUND_UP(data_offs + readlen, ecc->size); i++) {
1162*4882a593Smuzhiyun 		int data_off = i * ecc->size;
1163*4882a593Smuzhiyun 		int oob_off = i * (ecc->bytes + 4);
1164*4882a593Smuzhiyun 		u8 *data = bufpoi + data_off;
1165*4882a593Smuzhiyun 		u8 *oob = nand->oob_poi + oob_off;
1166*4882a593Smuzhiyun 
1167*4882a593Smuzhiyun 		ret = sunxi_nfc_hw_ecc_read_chunk(nand, data, data_off,
1168*4882a593Smuzhiyun 						  oob,
1169*4882a593Smuzhiyun 						  oob_off + mtd->writesize,
1170*4882a593Smuzhiyun 						  &cur_off, &max_bitflips, !i,
1171*4882a593Smuzhiyun 						  false, page);
1172*4882a593Smuzhiyun 		if (ret < 0)
1173*4882a593Smuzhiyun 			return ret;
1174*4882a593Smuzhiyun 	}
1175*4882a593Smuzhiyun 
1176*4882a593Smuzhiyun 	sunxi_nfc_hw_ecc_disable(nand);
1177*4882a593Smuzhiyun 
1178*4882a593Smuzhiyun 	return max_bitflips;
1179*4882a593Smuzhiyun }
1180*4882a593Smuzhiyun 
sunxi_nfc_hw_ecc_read_subpage_dma(struct nand_chip * nand,u32 data_offs,u32 readlen,u8 * buf,int page)1181*4882a593Smuzhiyun static int sunxi_nfc_hw_ecc_read_subpage_dma(struct nand_chip *nand,
1182*4882a593Smuzhiyun 					     u32 data_offs, u32 readlen,
1183*4882a593Smuzhiyun 					     u8 *buf, int page)
1184*4882a593Smuzhiyun {
1185*4882a593Smuzhiyun 	int nchunks = DIV_ROUND_UP(data_offs + readlen, nand->ecc.size);
1186*4882a593Smuzhiyun 	int ret;
1187*4882a593Smuzhiyun 
1188*4882a593Smuzhiyun 	sunxi_nfc_select_chip(nand, nand->cur_cs);
1189*4882a593Smuzhiyun 
1190*4882a593Smuzhiyun 	nand_read_page_op(nand, page, 0, NULL, 0);
1191*4882a593Smuzhiyun 
1192*4882a593Smuzhiyun 	ret = sunxi_nfc_hw_ecc_read_chunks_dma(nand, buf, false, page, nchunks);
1193*4882a593Smuzhiyun 	if (ret >= 0)
1194*4882a593Smuzhiyun 		return ret;
1195*4882a593Smuzhiyun 
1196*4882a593Smuzhiyun 	/* Fallback to PIO mode */
1197*4882a593Smuzhiyun 	return sunxi_nfc_hw_ecc_read_subpage(nand, data_offs, readlen,
1198*4882a593Smuzhiyun 					     buf, page);
1199*4882a593Smuzhiyun }
1200*4882a593Smuzhiyun 
sunxi_nfc_hw_ecc_write_page(struct nand_chip * nand,const uint8_t * buf,int oob_required,int page)1201*4882a593Smuzhiyun static int sunxi_nfc_hw_ecc_write_page(struct nand_chip *nand,
1202*4882a593Smuzhiyun 				       const uint8_t *buf, int oob_required,
1203*4882a593Smuzhiyun 				       int page)
1204*4882a593Smuzhiyun {
1205*4882a593Smuzhiyun 	struct mtd_info *mtd = nand_to_mtd(nand);
1206*4882a593Smuzhiyun 	struct nand_ecc_ctrl *ecc = &nand->ecc;
1207*4882a593Smuzhiyun 	int ret, i, cur_off = 0;
1208*4882a593Smuzhiyun 
1209*4882a593Smuzhiyun 	sunxi_nfc_select_chip(nand, nand->cur_cs);
1210*4882a593Smuzhiyun 
1211*4882a593Smuzhiyun 	nand_prog_page_begin_op(nand, page, 0, NULL, 0);
1212*4882a593Smuzhiyun 
1213*4882a593Smuzhiyun 	sunxi_nfc_hw_ecc_enable(nand);
1214*4882a593Smuzhiyun 
1215*4882a593Smuzhiyun 	for (i = 0; i < ecc->steps; i++) {
1216*4882a593Smuzhiyun 		int data_off = i * ecc->size;
1217*4882a593Smuzhiyun 		int oob_off = i * (ecc->bytes + 4);
1218*4882a593Smuzhiyun 		const u8 *data = buf + data_off;
1219*4882a593Smuzhiyun 		const u8 *oob = nand->oob_poi + oob_off;
1220*4882a593Smuzhiyun 
1221*4882a593Smuzhiyun 		ret = sunxi_nfc_hw_ecc_write_chunk(nand, data, data_off, oob,
1222*4882a593Smuzhiyun 						   oob_off + mtd->writesize,
1223*4882a593Smuzhiyun 						   &cur_off, !i, page);
1224*4882a593Smuzhiyun 		if (ret)
1225*4882a593Smuzhiyun 			return ret;
1226*4882a593Smuzhiyun 	}
1227*4882a593Smuzhiyun 
1228*4882a593Smuzhiyun 	if (oob_required || (nand->options & NAND_NEED_SCRAMBLING))
1229*4882a593Smuzhiyun 		sunxi_nfc_hw_ecc_write_extra_oob(nand, nand->oob_poi,
1230*4882a593Smuzhiyun 						 &cur_off, page);
1231*4882a593Smuzhiyun 
1232*4882a593Smuzhiyun 	sunxi_nfc_hw_ecc_disable(nand);
1233*4882a593Smuzhiyun 
1234*4882a593Smuzhiyun 	return nand_prog_page_end_op(nand);
1235*4882a593Smuzhiyun }
1236*4882a593Smuzhiyun 
sunxi_nfc_hw_ecc_write_subpage(struct nand_chip * nand,u32 data_offs,u32 data_len,const u8 * buf,int oob_required,int page)1237*4882a593Smuzhiyun static int sunxi_nfc_hw_ecc_write_subpage(struct nand_chip *nand,
1238*4882a593Smuzhiyun 					  u32 data_offs, u32 data_len,
1239*4882a593Smuzhiyun 					  const u8 *buf, int oob_required,
1240*4882a593Smuzhiyun 					  int page)
1241*4882a593Smuzhiyun {
1242*4882a593Smuzhiyun 	struct mtd_info *mtd = nand_to_mtd(nand);
1243*4882a593Smuzhiyun 	struct nand_ecc_ctrl *ecc = &nand->ecc;
1244*4882a593Smuzhiyun 	int ret, i, cur_off = 0;
1245*4882a593Smuzhiyun 
1246*4882a593Smuzhiyun 	sunxi_nfc_select_chip(nand, nand->cur_cs);
1247*4882a593Smuzhiyun 
1248*4882a593Smuzhiyun 	nand_prog_page_begin_op(nand, page, 0, NULL, 0);
1249*4882a593Smuzhiyun 
1250*4882a593Smuzhiyun 	sunxi_nfc_hw_ecc_enable(nand);
1251*4882a593Smuzhiyun 
1252*4882a593Smuzhiyun 	for (i = data_offs / ecc->size;
1253*4882a593Smuzhiyun 	     i < DIV_ROUND_UP(data_offs + data_len, ecc->size); i++) {
1254*4882a593Smuzhiyun 		int data_off = i * ecc->size;
1255*4882a593Smuzhiyun 		int oob_off = i * (ecc->bytes + 4);
1256*4882a593Smuzhiyun 		const u8 *data = buf + data_off;
1257*4882a593Smuzhiyun 		const u8 *oob = nand->oob_poi + oob_off;
1258*4882a593Smuzhiyun 
1259*4882a593Smuzhiyun 		ret = sunxi_nfc_hw_ecc_write_chunk(nand, data, data_off, oob,
1260*4882a593Smuzhiyun 						   oob_off + mtd->writesize,
1261*4882a593Smuzhiyun 						   &cur_off, !i, page);
1262*4882a593Smuzhiyun 		if (ret)
1263*4882a593Smuzhiyun 			return ret;
1264*4882a593Smuzhiyun 	}
1265*4882a593Smuzhiyun 
1266*4882a593Smuzhiyun 	sunxi_nfc_hw_ecc_disable(nand);
1267*4882a593Smuzhiyun 
1268*4882a593Smuzhiyun 	return nand_prog_page_end_op(nand);
1269*4882a593Smuzhiyun }
1270*4882a593Smuzhiyun 
sunxi_nfc_hw_ecc_write_page_dma(struct nand_chip * nand,const u8 * buf,int oob_required,int page)1271*4882a593Smuzhiyun static int sunxi_nfc_hw_ecc_write_page_dma(struct nand_chip *nand,
1272*4882a593Smuzhiyun 					   const u8 *buf,
1273*4882a593Smuzhiyun 					   int oob_required,
1274*4882a593Smuzhiyun 					   int page)
1275*4882a593Smuzhiyun {
1276*4882a593Smuzhiyun 	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
1277*4882a593Smuzhiyun 	struct nand_ecc_ctrl *ecc = &nand->ecc;
1278*4882a593Smuzhiyun 	struct scatterlist sg;
1279*4882a593Smuzhiyun 	int ret, i;
1280*4882a593Smuzhiyun 
1281*4882a593Smuzhiyun 	sunxi_nfc_select_chip(nand, nand->cur_cs);
1282*4882a593Smuzhiyun 
1283*4882a593Smuzhiyun 	ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
1284*4882a593Smuzhiyun 	if (ret)
1285*4882a593Smuzhiyun 		return ret;
1286*4882a593Smuzhiyun 
1287*4882a593Smuzhiyun 	ret = sunxi_nfc_dma_op_prepare(nfc, buf, ecc->size, ecc->steps,
1288*4882a593Smuzhiyun 				       DMA_TO_DEVICE, &sg);
1289*4882a593Smuzhiyun 	if (ret)
1290*4882a593Smuzhiyun 		goto pio_fallback;
1291*4882a593Smuzhiyun 
1292*4882a593Smuzhiyun 	for (i = 0; i < ecc->steps; i++) {
1293*4882a593Smuzhiyun 		const u8 *oob = nand->oob_poi + (i * (ecc->bytes + 4));
1294*4882a593Smuzhiyun 
1295*4882a593Smuzhiyun 		sunxi_nfc_hw_ecc_set_prot_oob_bytes(nand, oob, i, !i, page);
1296*4882a593Smuzhiyun 	}
1297*4882a593Smuzhiyun 
1298*4882a593Smuzhiyun 	nand_prog_page_begin_op(nand, page, 0, NULL, 0);
1299*4882a593Smuzhiyun 
1300*4882a593Smuzhiyun 	sunxi_nfc_hw_ecc_enable(nand);
1301*4882a593Smuzhiyun 	sunxi_nfc_randomizer_config(nand, page, false);
1302*4882a593Smuzhiyun 	sunxi_nfc_randomizer_enable(nand);
1303*4882a593Smuzhiyun 
1304*4882a593Smuzhiyun 	writel((NAND_CMD_RNDIN << 8) | NAND_CMD_PAGEPROG,
1305*4882a593Smuzhiyun 	       nfc->regs + NFC_REG_WCMD_SET);
1306*4882a593Smuzhiyun 
1307*4882a593Smuzhiyun 	dma_async_issue_pending(nfc->dmac);
1308*4882a593Smuzhiyun 
1309*4882a593Smuzhiyun 	writel(NFC_PAGE_OP | NFC_DATA_SWAP_METHOD |
1310*4882a593Smuzhiyun 	       NFC_DATA_TRANS | NFC_ACCESS_DIR,
1311*4882a593Smuzhiyun 	       nfc->regs + NFC_REG_CMD);
1312*4882a593Smuzhiyun 
1313*4882a593Smuzhiyun 	ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, false, 0);
1314*4882a593Smuzhiyun 	if (ret)
1315*4882a593Smuzhiyun 		dmaengine_terminate_all(nfc->dmac);
1316*4882a593Smuzhiyun 
1317*4882a593Smuzhiyun 	sunxi_nfc_randomizer_disable(nand);
1318*4882a593Smuzhiyun 	sunxi_nfc_hw_ecc_disable(nand);
1319*4882a593Smuzhiyun 
1320*4882a593Smuzhiyun 	sunxi_nfc_dma_op_cleanup(nfc, DMA_TO_DEVICE, &sg);
1321*4882a593Smuzhiyun 
1322*4882a593Smuzhiyun 	if (ret)
1323*4882a593Smuzhiyun 		return ret;
1324*4882a593Smuzhiyun 
1325*4882a593Smuzhiyun 	if (oob_required || (nand->options & NAND_NEED_SCRAMBLING))
1326*4882a593Smuzhiyun 		/* TODO: use DMA to transfer extra OOB bytes ? */
1327*4882a593Smuzhiyun 		sunxi_nfc_hw_ecc_write_extra_oob(nand, nand->oob_poi,
1328*4882a593Smuzhiyun 						 NULL, page);
1329*4882a593Smuzhiyun 
1330*4882a593Smuzhiyun 	return nand_prog_page_end_op(nand);
1331*4882a593Smuzhiyun 
1332*4882a593Smuzhiyun pio_fallback:
1333*4882a593Smuzhiyun 	return sunxi_nfc_hw_ecc_write_page(nand, buf, oob_required, page);
1334*4882a593Smuzhiyun }
1335*4882a593Smuzhiyun 
sunxi_nfc_hw_ecc_read_oob(struct nand_chip * nand,int page)1336*4882a593Smuzhiyun static int sunxi_nfc_hw_ecc_read_oob(struct nand_chip *nand, int page)
1337*4882a593Smuzhiyun {
1338*4882a593Smuzhiyun 	u8 *buf = nand_get_data_buf(nand);
1339*4882a593Smuzhiyun 
1340*4882a593Smuzhiyun 	return nand->ecc.read_page(nand, buf, 1, page);
1341*4882a593Smuzhiyun }
1342*4882a593Smuzhiyun 
sunxi_nfc_hw_ecc_write_oob(struct nand_chip * nand,int page)1343*4882a593Smuzhiyun static int sunxi_nfc_hw_ecc_write_oob(struct nand_chip *nand, int page)
1344*4882a593Smuzhiyun {
1345*4882a593Smuzhiyun 	struct mtd_info *mtd = nand_to_mtd(nand);
1346*4882a593Smuzhiyun 	u8 *buf = nand_get_data_buf(nand);
1347*4882a593Smuzhiyun 	int ret;
1348*4882a593Smuzhiyun 
1349*4882a593Smuzhiyun 	memset(buf, 0xff, mtd->writesize);
1350*4882a593Smuzhiyun 	ret = nand->ecc.write_page(nand, buf, 1, page);
1351*4882a593Smuzhiyun 	if (ret)
1352*4882a593Smuzhiyun 		return ret;
1353*4882a593Smuzhiyun 
1354*4882a593Smuzhiyun 	/* Send command to program the OOB data */
1355*4882a593Smuzhiyun 	return nand_prog_page_end_op(nand);
1356*4882a593Smuzhiyun }
1357*4882a593Smuzhiyun 
1358*4882a593Smuzhiyun static const s32 tWB_lut[] = {6, 12, 16, 20};
1359*4882a593Smuzhiyun static const s32 tRHW_lut[] = {4, 8, 12, 20};
1360*4882a593Smuzhiyun 
_sunxi_nand_lookup_timing(const s32 * lut,int lut_size,u32 duration,u32 clk_period)1361*4882a593Smuzhiyun static int _sunxi_nand_lookup_timing(const s32 *lut, int lut_size, u32 duration,
1362*4882a593Smuzhiyun 		u32 clk_period)
1363*4882a593Smuzhiyun {
1364*4882a593Smuzhiyun 	u32 clk_cycles = DIV_ROUND_UP(duration, clk_period);
1365*4882a593Smuzhiyun 	int i;
1366*4882a593Smuzhiyun 
1367*4882a593Smuzhiyun 	for (i = 0; i < lut_size; i++) {
1368*4882a593Smuzhiyun 		if (clk_cycles <= lut[i])
1369*4882a593Smuzhiyun 			return i;
1370*4882a593Smuzhiyun 	}
1371*4882a593Smuzhiyun 
1372*4882a593Smuzhiyun 	/* Doesn't fit */
1373*4882a593Smuzhiyun 	return -EINVAL;
1374*4882a593Smuzhiyun }
1375*4882a593Smuzhiyun 
1376*4882a593Smuzhiyun #define sunxi_nand_lookup_timing(l, p, c) \
1377*4882a593Smuzhiyun 			_sunxi_nand_lookup_timing(l, ARRAY_SIZE(l), p, c)
1378*4882a593Smuzhiyun 
sunxi_nfc_setup_interface(struct nand_chip * nand,int csline,const struct nand_interface_config * conf)1379*4882a593Smuzhiyun static int sunxi_nfc_setup_interface(struct nand_chip *nand, int csline,
1380*4882a593Smuzhiyun 				     const struct nand_interface_config *conf)
1381*4882a593Smuzhiyun {
1382*4882a593Smuzhiyun 	struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
1383*4882a593Smuzhiyun 	struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
1384*4882a593Smuzhiyun 	const struct nand_sdr_timings *timings;
1385*4882a593Smuzhiyun 	u32 min_clk_period = 0;
1386*4882a593Smuzhiyun 	s32 tWB, tADL, tWHR, tRHW, tCAD;
1387*4882a593Smuzhiyun 	long real_clk_rate;
1388*4882a593Smuzhiyun 
1389*4882a593Smuzhiyun 	timings = nand_get_sdr_timings(conf);
1390*4882a593Smuzhiyun 	if (IS_ERR(timings))
1391*4882a593Smuzhiyun 		return -ENOTSUPP;
1392*4882a593Smuzhiyun 
1393*4882a593Smuzhiyun 	/* T1 <=> tCLS */
1394*4882a593Smuzhiyun 	if (timings->tCLS_min > min_clk_period)
1395*4882a593Smuzhiyun 		min_clk_period = timings->tCLS_min;
1396*4882a593Smuzhiyun 
1397*4882a593Smuzhiyun 	/* T2 <=> tCLH */
1398*4882a593Smuzhiyun 	if (timings->tCLH_min > min_clk_period)
1399*4882a593Smuzhiyun 		min_clk_period = timings->tCLH_min;
1400*4882a593Smuzhiyun 
1401*4882a593Smuzhiyun 	/* T3 <=> tCS */
1402*4882a593Smuzhiyun 	if (timings->tCS_min > min_clk_period)
1403*4882a593Smuzhiyun 		min_clk_period = timings->tCS_min;
1404*4882a593Smuzhiyun 
1405*4882a593Smuzhiyun 	/* T4 <=> tCH */
1406*4882a593Smuzhiyun 	if (timings->tCH_min > min_clk_period)
1407*4882a593Smuzhiyun 		min_clk_period = timings->tCH_min;
1408*4882a593Smuzhiyun 
1409*4882a593Smuzhiyun 	/* T5 <=> tWP */
1410*4882a593Smuzhiyun 	if (timings->tWP_min > min_clk_period)
1411*4882a593Smuzhiyun 		min_clk_period = timings->tWP_min;
1412*4882a593Smuzhiyun 
1413*4882a593Smuzhiyun 	/* T6 <=> tWH */
1414*4882a593Smuzhiyun 	if (timings->tWH_min > min_clk_period)
1415*4882a593Smuzhiyun 		min_clk_period = timings->tWH_min;
1416*4882a593Smuzhiyun 
1417*4882a593Smuzhiyun 	/* T7 <=> tALS */
1418*4882a593Smuzhiyun 	if (timings->tALS_min > min_clk_period)
1419*4882a593Smuzhiyun 		min_clk_period = timings->tALS_min;
1420*4882a593Smuzhiyun 
1421*4882a593Smuzhiyun 	/* T8 <=> tDS */
1422*4882a593Smuzhiyun 	if (timings->tDS_min > min_clk_period)
1423*4882a593Smuzhiyun 		min_clk_period = timings->tDS_min;
1424*4882a593Smuzhiyun 
1425*4882a593Smuzhiyun 	/* T9 <=> tDH */
1426*4882a593Smuzhiyun 	if (timings->tDH_min > min_clk_period)
1427*4882a593Smuzhiyun 		min_clk_period = timings->tDH_min;
1428*4882a593Smuzhiyun 
1429*4882a593Smuzhiyun 	/* T10 <=> tRR */
1430*4882a593Smuzhiyun 	if (timings->tRR_min > (min_clk_period * 3))
1431*4882a593Smuzhiyun 		min_clk_period = DIV_ROUND_UP(timings->tRR_min, 3);
1432*4882a593Smuzhiyun 
1433*4882a593Smuzhiyun 	/* T11 <=> tALH */
1434*4882a593Smuzhiyun 	if (timings->tALH_min > min_clk_period)
1435*4882a593Smuzhiyun 		min_clk_period = timings->tALH_min;
1436*4882a593Smuzhiyun 
1437*4882a593Smuzhiyun 	/* T12 <=> tRP */
1438*4882a593Smuzhiyun 	if (timings->tRP_min > min_clk_period)
1439*4882a593Smuzhiyun 		min_clk_period = timings->tRP_min;
1440*4882a593Smuzhiyun 
1441*4882a593Smuzhiyun 	/* T13 <=> tREH */
1442*4882a593Smuzhiyun 	if (timings->tREH_min > min_clk_period)
1443*4882a593Smuzhiyun 		min_clk_period = timings->tREH_min;
1444*4882a593Smuzhiyun 
1445*4882a593Smuzhiyun 	/* T14 <=> tRC */
1446*4882a593Smuzhiyun 	if (timings->tRC_min > (min_clk_period * 2))
1447*4882a593Smuzhiyun 		min_clk_period = DIV_ROUND_UP(timings->tRC_min, 2);
1448*4882a593Smuzhiyun 
1449*4882a593Smuzhiyun 	/* T15 <=> tWC */
1450*4882a593Smuzhiyun 	if (timings->tWC_min > (min_clk_period * 2))
1451*4882a593Smuzhiyun 		min_clk_period = DIV_ROUND_UP(timings->tWC_min, 2);
1452*4882a593Smuzhiyun 
1453*4882a593Smuzhiyun 	/* T16 - T19 + tCAD */
1454*4882a593Smuzhiyun 	if (timings->tWB_max > (min_clk_period * 20))
1455*4882a593Smuzhiyun 		min_clk_period = DIV_ROUND_UP(timings->tWB_max, 20);
1456*4882a593Smuzhiyun 
1457*4882a593Smuzhiyun 	if (timings->tADL_min > (min_clk_period * 32))
1458*4882a593Smuzhiyun 		min_clk_period = DIV_ROUND_UP(timings->tADL_min, 32);
1459*4882a593Smuzhiyun 
1460*4882a593Smuzhiyun 	if (timings->tWHR_min > (min_clk_period * 32))
1461*4882a593Smuzhiyun 		min_clk_period = DIV_ROUND_UP(timings->tWHR_min, 32);
1462*4882a593Smuzhiyun 
1463*4882a593Smuzhiyun 	if (timings->tRHW_min > (min_clk_period * 20))
1464*4882a593Smuzhiyun 		min_clk_period = DIV_ROUND_UP(timings->tRHW_min, 20);
1465*4882a593Smuzhiyun 
1466*4882a593Smuzhiyun 	/*
1467*4882a593Smuzhiyun 	 * In non-EDO, tREA should be less than tRP to guarantee that the
1468*4882a593Smuzhiyun 	 * controller does not sample the IO lines too early. Unfortunately,
1469*4882a593Smuzhiyun 	 * the sunxi NAND controller does not allow us to have different
1470*4882a593Smuzhiyun 	 * values for tRP and tREH (tRP = tREH = tRW / 2).
1471*4882a593Smuzhiyun 	 *
1472*4882a593Smuzhiyun 	 * We have 2 options to overcome this limitation:
1473*4882a593Smuzhiyun 	 *
1474*4882a593Smuzhiyun 	 * 1/ Extend tRC to fulfil the tREA <= tRC / 2 constraint
1475*4882a593Smuzhiyun 	 * 2/ Use EDO mode (only works if timings->tRLOH > 0)
1476*4882a593Smuzhiyun 	 */
1477*4882a593Smuzhiyun 	if (timings->tREA_max > min_clk_period && !timings->tRLOH_min)
1478*4882a593Smuzhiyun 		min_clk_period = timings->tREA_max;
1479*4882a593Smuzhiyun 
1480*4882a593Smuzhiyun 	tWB  = sunxi_nand_lookup_timing(tWB_lut, timings->tWB_max,
1481*4882a593Smuzhiyun 					min_clk_period);
1482*4882a593Smuzhiyun 	if (tWB < 0) {
1483*4882a593Smuzhiyun 		dev_err(nfc->dev, "unsupported tWB\n");
1484*4882a593Smuzhiyun 		return tWB;
1485*4882a593Smuzhiyun 	}
1486*4882a593Smuzhiyun 
1487*4882a593Smuzhiyun 	tADL = DIV_ROUND_UP(timings->tADL_min, min_clk_period) >> 3;
1488*4882a593Smuzhiyun 	if (tADL > 3) {
1489*4882a593Smuzhiyun 		dev_err(nfc->dev, "unsupported tADL\n");
1490*4882a593Smuzhiyun 		return -EINVAL;
1491*4882a593Smuzhiyun 	}
1492*4882a593Smuzhiyun 
1493*4882a593Smuzhiyun 	tWHR = DIV_ROUND_UP(timings->tWHR_min, min_clk_period) >> 3;
1494*4882a593Smuzhiyun 	if (tWHR > 3) {
1495*4882a593Smuzhiyun 		dev_err(nfc->dev, "unsupported tWHR\n");
1496*4882a593Smuzhiyun 		return -EINVAL;
1497*4882a593Smuzhiyun 	}
1498*4882a593Smuzhiyun 
1499*4882a593Smuzhiyun 	tRHW = sunxi_nand_lookup_timing(tRHW_lut, timings->tRHW_min,
1500*4882a593Smuzhiyun 					min_clk_period);
1501*4882a593Smuzhiyun 	if (tRHW < 0) {
1502*4882a593Smuzhiyun 		dev_err(nfc->dev, "unsupported tRHW\n");
1503*4882a593Smuzhiyun 		return tRHW;
1504*4882a593Smuzhiyun 	}
1505*4882a593Smuzhiyun 
1506*4882a593Smuzhiyun 	if (csline == NAND_DATA_IFACE_CHECK_ONLY)
1507*4882a593Smuzhiyun 		return 0;
1508*4882a593Smuzhiyun 
1509*4882a593Smuzhiyun 	/*
1510*4882a593Smuzhiyun 	 * TODO: according to ONFI specs this value only applies for DDR NAND,
1511*4882a593Smuzhiyun 	 * but Allwinner seems to set this to 0x7. Mimic them for now.
1512*4882a593Smuzhiyun 	 */
1513*4882a593Smuzhiyun 	tCAD = 0x7;
1514*4882a593Smuzhiyun 
1515*4882a593Smuzhiyun 	/* TODO: A83 has some more bits for CDQSS, CS, CLHZ, CCS, WC */
1516*4882a593Smuzhiyun 	sunxi_nand->timing_cfg = NFC_TIMING_CFG(tWB, tADL, tWHR, tRHW, tCAD);
1517*4882a593Smuzhiyun 
1518*4882a593Smuzhiyun 	/* Convert min_clk_period from picoseconds to nanoseconds */
1519*4882a593Smuzhiyun 	min_clk_period = DIV_ROUND_UP(min_clk_period, 1000);
1520*4882a593Smuzhiyun 
1521*4882a593Smuzhiyun 	/*
1522*4882a593Smuzhiyun 	 * Unlike what is stated in Allwinner datasheet, the clk_rate should
1523*4882a593Smuzhiyun 	 * be set to (1 / min_clk_period), and not (2 / min_clk_period).
1524*4882a593Smuzhiyun 	 * This new formula was verified with a scope and validated by
1525*4882a593Smuzhiyun 	 * Allwinner engineers.
1526*4882a593Smuzhiyun 	 */
1527*4882a593Smuzhiyun 	sunxi_nand->clk_rate = NSEC_PER_SEC / min_clk_period;
1528*4882a593Smuzhiyun 	real_clk_rate = clk_round_rate(nfc->mod_clk, sunxi_nand->clk_rate);
1529*4882a593Smuzhiyun 	if (real_clk_rate <= 0) {
1530*4882a593Smuzhiyun 		dev_err(nfc->dev, "Unable to round clk %lu\n",
1531*4882a593Smuzhiyun 			sunxi_nand->clk_rate);
1532*4882a593Smuzhiyun 		return -EINVAL;
1533*4882a593Smuzhiyun 	}
1534*4882a593Smuzhiyun 
1535*4882a593Smuzhiyun 	sunxi_nand->timing_ctl = 0;
1536*4882a593Smuzhiyun 
1537*4882a593Smuzhiyun 	/*
1538*4882a593Smuzhiyun 	 * ONFI specification 3.1, paragraph 4.15.2 dictates that EDO data
1539*4882a593Smuzhiyun 	 * output cycle timings shall be used if the host drives tRC less than
1540*4882a593Smuzhiyun 	 * 30 ns. We should also use EDO mode if tREA is bigger than tRP.
1541*4882a593Smuzhiyun 	 */
1542*4882a593Smuzhiyun 	min_clk_period = NSEC_PER_SEC / real_clk_rate;
1543*4882a593Smuzhiyun 	if (min_clk_period * 2 < 30 || min_clk_period * 1000 < timings->tREA_max)
1544*4882a593Smuzhiyun 		sunxi_nand->timing_ctl = NFC_TIMING_CTL_EDO;
1545*4882a593Smuzhiyun 
1546*4882a593Smuzhiyun 	return 0;
1547*4882a593Smuzhiyun }
1548*4882a593Smuzhiyun 
sunxi_nand_ooblayout_ecc(struct mtd_info * mtd,int section,struct mtd_oob_region * oobregion)1549*4882a593Smuzhiyun static int sunxi_nand_ooblayout_ecc(struct mtd_info *mtd, int section,
1550*4882a593Smuzhiyun 				    struct mtd_oob_region *oobregion)
1551*4882a593Smuzhiyun {
1552*4882a593Smuzhiyun 	struct nand_chip *nand = mtd_to_nand(mtd);
1553*4882a593Smuzhiyun 	struct nand_ecc_ctrl *ecc = &nand->ecc;
1554*4882a593Smuzhiyun 
1555*4882a593Smuzhiyun 	if (section >= ecc->steps)
1556*4882a593Smuzhiyun 		return -ERANGE;
1557*4882a593Smuzhiyun 
1558*4882a593Smuzhiyun 	oobregion->offset = section * (ecc->bytes + 4) + 4;
1559*4882a593Smuzhiyun 	oobregion->length = ecc->bytes;
1560*4882a593Smuzhiyun 
1561*4882a593Smuzhiyun 	return 0;
1562*4882a593Smuzhiyun }
1563*4882a593Smuzhiyun 
sunxi_nand_ooblayout_free(struct mtd_info * mtd,int section,struct mtd_oob_region * oobregion)1564*4882a593Smuzhiyun static int sunxi_nand_ooblayout_free(struct mtd_info *mtd, int section,
1565*4882a593Smuzhiyun 				     struct mtd_oob_region *oobregion)
1566*4882a593Smuzhiyun {
1567*4882a593Smuzhiyun 	struct nand_chip *nand = mtd_to_nand(mtd);
1568*4882a593Smuzhiyun 	struct nand_ecc_ctrl *ecc = &nand->ecc;
1569*4882a593Smuzhiyun 
1570*4882a593Smuzhiyun 	if (section > ecc->steps)
1571*4882a593Smuzhiyun 		return -ERANGE;
1572*4882a593Smuzhiyun 
1573*4882a593Smuzhiyun 	/*
1574*4882a593Smuzhiyun 	 * The first 2 bytes are used for BB markers, hence we
1575*4882a593Smuzhiyun 	 * only have 2 bytes available in the first user data
1576*4882a593Smuzhiyun 	 * section.
1577*4882a593Smuzhiyun 	 */
1578*4882a593Smuzhiyun 	if (!section && ecc->engine_type == NAND_ECC_ENGINE_TYPE_ON_HOST) {
1579*4882a593Smuzhiyun 		oobregion->offset = 2;
1580*4882a593Smuzhiyun 		oobregion->length = 2;
1581*4882a593Smuzhiyun 
1582*4882a593Smuzhiyun 		return 0;
1583*4882a593Smuzhiyun 	}
1584*4882a593Smuzhiyun 
1585*4882a593Smuzhiyun 	oobregion->offset = section * (ecc->bytes + 4);
1586*4882a593Smuzhiyun 
1587*4882a593Smuzhiyun 	if (section < ecc->steps)
1588*4882a593Smuzhiyun 		oobregion->length = 4;
1589*4882a593Smuzhiyun 	else
1590*4882a593Smuzhiyun 		oobregion->offset = mtd->oobsize - oobregion->offset;
1591*4882a593Smuzhiyun 
1592*4882a593Smuzhiyun 	return 0;
1593*4882a593Smuzhiyun }
1594*4882a593Smuzhiyun 
1595*4882a593Smuzhiyun static const struct mtd_ooblayout_ops sunxi_nand_ooblayout_ops = {
1596*4882a593Smuzhiyun 	.ecc = sunxi_nand_ooblayout_ecc,
1597*4882a593Smuzhiyun 	.free = sunxi_nand_ooblayout_free,
1598*4882a593Smuzhiyun };
1599*4882a593Smuzhiyun 
sunxi_nand_hw_ecc_ctrl_cleanup(struct nand_ecc_ctrl * ecc)1600*4882a593Smuzhiyun static void sunxi_nand_hw_ecc_ctrl_cleanup(struct nand_ecc_ctrl *ecc)
1601*4882a593Smuzhiyun {
1602*4882a593Smuzhiyun 	kfree(ecc->priv);
1603*4882a593Smuzhiyun }
1604*4882a593Smuzhiyun 
sunxi_nand_hw_ecc_ctrl_init(struct nand_chip * nand,struct nand_ecc_ctrl * ecc,struct device_node * np)1605*4882a593Smuzhiyun static int sunxi_nand_hw_ecc_ctrl_init(struct nand_chip *nand,
1606*4882a593Smuzhiyun 				       struct nand_ecc_ctrl *ecc,
1607*4882a593Smuzhiyun 				       struct device_node *np)
1608*4882a593Smuzhiyun {
1609*4882a593Smuzhiyun 	static const u8 strengths[] = { 16, 24, 28, 32, 40, 48, 56, 60, 64 };
1610*4882a593Smuzhiyun 	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
1611*4882a593Smuzhiyun 	struct mtd_info *mtd = nand_to_mtd(nand);
1612*4882a593Smuzhiyun 	struct nand_device *nanddev = mtd_to_nanddev(mtd);
1613*4882a593Smuzhiyun 	struct sunxi_nand_hw_ecc *data;
1614*4882a593Smuzhiyun 	int nsectors;
1615*4882a593Smuzhiyun 	int ret;
1616*4882a593Smuzhiyun 	int i;
1617*4882a593Smuzhiyun 
1618*4882a593Smuzhiyun 	if (nanddev->ecc.user_conf.flags & NAND_ECC_MAXIMIZE_STRENGTH) {
1619*4882a593Smuzhiyun 		int bytes;
1620*4882a593Smuzhiyun 
1621*4882a593Smuzhiyun 		ecc->size = 1024;
1622*4882a593Smuzhiyun 		nsectors = mtd->writesize / ecc->size;
1623*4882a593Smuzhiyun 
1624*4882a593Smuzhiyun 		/* Reserve 2 bytes for the BBM */
1625*4882a593Smuzhiyun 		bytes = (mtd->oobsize - 2) / nsectors;
1626*4882a593Smuzhiyun 
1627*4882a593Smuzhiyun 		/* 4 non-ECC bytes are added before each ECC bytes section */
1628*4882a593Smuzhiyun 		bytes -= 4;
1629*4882a593Smuzhiyun 
1630*4882a593Smuzhiyun 		/* and bytes has to be even. */
1631*4882a593Smuzhiyun 		if (bytes % 2)
1632*4882a593Smuzhiyun 			bytes--;
1633*4882a593Smuzhiyun 
1634*4882a593Smuzhiyun 		ecc->strength = bytes * 8 / fls(8 * ecc->size);
1635*4882a593Smuzhiyun 
1636*4882a593Smuzhiyun 		for (i = 0; i < ARRAY_SIZE(strengths); i++) {
1637*4882a593Smuzhiyun 			if (strengths[i] > ecc->strength)
1638*4882a593Smuzhiyun 				break;
1639*4882a593Smuzhiyun 		}
1640*4882a593Smuzhiyun 
1641*4882a593Smuzhiyun 		if (!i)
1642*4882a593Smuzhiyun 			ecc->strength = 0;
1643*4882a593Smuzhiyun 		else
1644*4882a593Smuzhiyun 			ecc->strength = strengths[i - 1];
1645*4882a593Smuzhiyun 	}
1646*4882a593Smuzhiyun 
1647*4882a593Smuzhiyun 	if (ecc->size != 512 && ecc->size != 1024)
1648*4882a593Smuzhiyun 		return -EINVAL;
1649*4882a593Smuzhiyun 
1650*4882a593Smuzhiyun 	data = kzalloc(sizeof(*data), GFP_KERNEL);
1651*4882a593Smuzhiyun 	if (!data)
1652*4882a593Smuzhiyun 		return -ENOMEM;
1653*4882a593Smuzhiyun 
1654*4882a593Smuzhiyun 	/* Prefer 1k ECC chunk over 512 ones */
1655*4882a593Smuzhiyun 	if (ecc->size == 512 && mtd->writesize > 512) {
1656*4882a593Smuzhiyun 		ecc->size = 1024;
1657*4882a593Smuzhiyun 		ecc->strength *= 2;
1658*4882a593Smuzhiyun 	}
1659*4882a593Smuzhiyun 
1660*4882a593Smuzhiyun 	/* Add ECC info retrieval from DT */
1661*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(strengths); i++) {
1662*4882a593Smuzhiyun 		if (ecc->strength <= strengths[i]) {
1663*4882a593Smuzhiyun 			/*
1664*4882a593Smuzhiyun 			 * Update ecc->strength value with the actual strength
1665*4882a593Smuzhiyun 			 * that will be used by the ECC engine.
1666*4882a593Smuzhiyun 			 */
1667*4882a593Smuzhiyun 			ecc->strength = strengths[i];
1668*4882a593Smuzhiyun 			break;
1669*4882a593Smuzhiyun 		}
1670*4882a593Smuzhiyun 	}
1671*4882a593Smuzhiyun 
1672*4882a593Smuzhiyun 	if (i >= ARRAY_SIZE(strengths)) {
1673*4882a593Smuzhiyun 		dev_err(nfc->dev, "unsupported strength\n");
1674*4882a593Smuzhiyun 		ret = -ENOTSUPP;
1675*4882a593Smuzhiyun 		goto err;
1676*4882a593Smuzhiyun 	}
1677*4882a593Smuzhiyun 
1678*4882a593Smuzhiyun 	data->mode = i;
1679*4882a593Smuzhiyun 
1680*4882a593Smuzhiyun 	/* HW ECC always request ECC bytes for 1024 bytes blocks */
1681*4882a593Smuzhiyun 	ecc->bytes = DIV_ROUND_UP(ecc->strength * fls(8 * 1024), 8);
1682*4882a593Smuzhiyun 
1683*4882a593Smuzhiyun 	/* HW ECC always work with even numbers of ECC bytes */
1684*4882a593Smuzhiyun 	ecc->bytes = ALIGN(ecc->bytes, 2);
1685*4882a593Smuzhiyun 
1686*4882a593Smuzhiyun 	nsectors = mtd->writesize / ecc->size;
1687*4882a593Smuzhiyun 
1688*4882a593Smuzhiyun 	if (mtd->oobsize < ((ecc->bytes + 4) * nsectors)) {
1689*4882a593Smuzhiyun 		ret = -EINVAL;
1690*4882a593Smuzhiyun 		goto err;
1691*4882a593Smuzhiyun 	}
1692*4882a593Smuzhiyun 
1693*4882a593Smuzhiyun 	ecc->read_oob = sunxi_nfc_hw_ecc_read_oob;
1694*4882a593Smuzhiyun 	ecc->write_oob = sunxi_nfc_hw_ecc_write_oob;
1695*4882a593Smuzhiyun 	mtd_set_ooblayout(mtd, &sunxi_nand_ooblayout_ops);
1696*4882a593Smuzhiyun 	ecc->priv = data;
1697*4882a593Smuzhiyun 
1698*4882a593Smuzhiyun 	if (nfc->dmac) {
1699*4882a593Smuzhiyun 		ecc->read_page = sunxi_nfc_hw_ecc_read_page_dma;
1700*4882a593Smuzhiyun 		ecc->read_subpage = sunxi_nfc_hw_ecc_read_subpage_dma;
1701*4882a593Smuzhiyun 		ecc->write_page = sunxi_nfc_hw_ecc_write_page_dma;
1702*4882a593Smuzhiyun 		nand->options |= NAND_USES_DMA;
1703*4882a593Smuzhiyun 	} else {
1704*4882a593Smuzhiyun 		ecc->read_page = sunxi_nfc_hw_ecc_read_page;
1705*4882a593Smuzhiyun 		ecc->read_subpage = sunxi_nfc_hw_ecc_read_subpage;
1706*4882a593Smuzhiyun 		ecc->write_page = sunxi_nfc_hw_ecc_write_page;
1707*4882a593Smuzhiyun 	}
1708*4882a593Smuzhiyun 
1709*4882a593Smuzhiyun 	/* TODO: support DMA for raw accesses and subpage write */
1710*4882a593Smuzhiyun 	ecc->write_subpage = sunxi_nfc_hw_ecc_write_subpage;
1711*4882a593Smuzhiyun 	ecc->read_oob_raw = nand_read_oob_std;
1712*4882a593Smuzhiyun 	ecc->write_oob_raw = nand_write_oob_std;
1713*4882a593Smuzhiyun 
1714*4882a593Smuzhiyun 	return 0;
1715*4882a593Smuzhiyun 
1716*4882a593Smuzhiyun err:
1717*4882a593Smuzhiyun 	kfree(data);
1718*4882a593Smuzhiyun 
1719*4882a593Smuzhiyun 	return ret;
1720*4882a593Smuzhiyun }
1721*4882a593Smuzhiyun 
sunxi_nand_ecc_cleanup(struct nand_ecc_ctrl * ecc)1722*4882a593Smuzhiyun static void sunxi_nand_ecc_cleanup(struct nand_ecc_ctrl *ecc)
1723*4882a593Smuzhiyun {
1724*4882a593Smuzhiyun 	switch (ecc->engine_type) {
1725*4882a593Smuzhiyun 	case NAND_ECC_ENGINE_TYPE_ON_HOST:
1726*4882a593Smuzhiyun 		sunxi_nand_hw_ecc_ctrl_cleanup(ecc);
1727*4882a593Smuzhiyun 		break;
1728*4882a593Smuzhiyun 	case NAND_ECC_ENGINE_TYPE_NONE:
1729*4882a593Smuzhiyun 	default:
1730*4882a593Smuzhiyun 		break;
1731*4882a593Smuzhiyun 	}
1732*4882a593Smuzhiyun }
1733*4882a593Smuzhiyun 
sunxi_nand_attach_chip(struct nand_chip * nand)1734*4882a593Smuzhiyun static int sunxi_nand_attach_chip(struct nand_chip *nand)
1735*4882a593Smuzhiyun {
1736*4882a593Smuzhiyun 	const struct nand_ecc_props *requirements =
1737*4882a593Smuzhiyun 		nanddev_get_ecc_requirements(&nand->base);
1738*4882a593Smuzhiyun 	struct nand_ecc_ctrl *ecc = &nand->ecc;
1739*4882a593Smuzhiyun 	struct device_node *np = nand_get_flash_node(nand);
1740*4882a593Smuzhiyun 	int ret;
1741*4882a593Smuzhiyun 
1742*4882a593Smuzhiyun 	if (nand->bbt_options & NAND_BBT_USE_FLASH)
1743*4882a593Smuzhiyun 		nand->bbt_options |= NAND_BBT_NO_OOB;
1744*4882a593Smuzhiyun 
1745*4882a593Smuzhiyun 	if (nand->options & NAND_NEED_SCRAMBLING)
1746*4882a593Smuzhiyun 		nand->options |= NAND_NO_SUBPAGE_WRITE;
1747*4882a593Smuzhiyun 
1748*4882a593Smuzhiyun 	nand->options |= NAND_SUBPAGE_READ;
1749*4882a593Smuzhiyun 
1750*4882a593Smuzhiyun 	if (!ecc->size) {
1751*4882a593Smuzhiyun 		ecc->size = requirements->step_size;
1752*4882a593Smuzhiyun 		ecc->strength = requirements->strength;
1753*4882a593Smuzhiyun 	}
1754*4882a593Smuzhiyun 
1755*4882a593Smuzhiyun 	if (!ecc->size || !ecc->strength)
1756*4882a593Smuzhiyun 		return -EINVAL;
1757*4882a593Smuzhiyun 
1758*4882a593Smuzhiyun 	switch (ecc->engine_type) {
1759*4882a593Smuzhiyun 	case NAND_ECC_ENGINE_TYPE_ON_HOST:
1760*4882a593Smuzhiyun 		ret = sunxi_nand_hw_ecc_ctrl_init(nand, ecc, np);
1761*4882a593Smuzhiyun 		if (ret)
1762*4882a593Smuzhiyun 			return ret;
1763*4882a593Smuzhiyun 		break;
1764*4882a593Smuzhiyun 	case NAND_ECC_ENGINE_TYPE_NONE:
1765*4882a593Smuzhiyun 	case NAND_ECC_ENGINE_TYPE_SOFT:
1766*4882a593Smuzhiyun 		break;
1767*4882a593Smuzhiyun 	default:
1768*4882a593Smuzhiyun 		return -EINVAL;
1769*4882a593Smuzhiyun 	}
1770*4882a593Smuzhiyun 
1771*4882a593Smuzhiyun 	return 0;
1772*4882a593Smuzhiyun }
1773*4882a593Smuzhiyun 
sunxi_nfc_exec_subop(struct nand_chip * nand,const struct nand_subop * subop)1774*4882a593Smuzhiyun static int sunxi_nfc_exec_subop(struct nand_chip *nand,
1775*4882a593Smuzhiyun 				const struct nand_subop *subop)
1776*4882a593Smuzhiyun {
1777*4882a593Smuzhiyun 	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
1778*4882a593Smuzhiyun 	u32 cmd = 0, extcmd = 0, cnt = 0, addrs[2] = { };
1779*4882a593Smuzhiyun 	unsigned int i, j, remaining, start;
1780*4882a593Smuzhiyun 	void *inbuf = NULL;
1781*4882a593Smuzhiyun 	int ret;
1782*4882a593Smuzhiyun 
1783*4882a593Smuzhiyun 	for (i = 0; i < subop->ninstrs; i++) {
1784*4882a593Smuzhiyun 		const struct nand_op_instr *instr = &subop->instrs[i];
1785*4882a593Smuzhiyun 
1786*4882a593Smuzhiyun 		switch (instr->type) {
1787*4882a593Smuzhiyun 		case NAND_OP_CMD_INSTR:
1788*4882a593Smuzhiyun 			if (cmd & NFC_SEND_CMD1) {
1789*4882a593Smuzhiyun 				if (WARN_ON(cmd & NFC_SEND_CMD2))
1790*4882a593Smuzhiyun 					return -EINVAL;
1791*4882a593Smuzhiyun 
1792*4882a593Smuzhiyun 				cmd |= NFC_SEND_CMD2;
1793*4882a593Smuzhiyun 				extcmd |= instr->ctx.cmd.opcode;
1794*4882a593Smuzhiyun 			} else {
1795*4882a593Smuzhiyun 				cmd |= NFC_SEND_CMD1 |
1796*4882a593Smuzhiyun 				       NFC_CMD(instr->ctx.cmd.opcode);
1797*4882a593Smuzhiyun 			}
1798*4882a593Smuzhiyun 			break;
1799*4882a593Smuzhiyun 
1800*4882a593Smuzhiyun 		case NAND_OP_ADDR_INSTR:
1801*4882a593Smuzhiyun 			remaining = nand_subop_get_num_addr_cyc(subop, i);
1802*4882a593Smuzhiyun 			start = nand_subop_get_addr_start_off(subop, i);
1803*4882a593Smuzhiyun 			for (j = 0; j < 8 && j + start < remaining; j++) {
1804*4882a593Smuzhiyun 				u32 addr = instr->ctx.addr.addrs[j + start];
1805*4882a593Smuzhiyun 
1806*4882a593Smuzhiyun 				addrs[j / 4] |= addr << (j % 4) * 8;
1807*4882a593Smuzhiyun 			}
1808*4882a593Smuzhiyun 
1809*4882a593Smuzhiyun 			if (j)
1810*4882a593Smuzhiyun 				cmd |= NFC_SEND_ADR | NFC_ADR_NUM(j);
1811*4882a593Smuzhiyun 
1812*4882a593Smuzhiyun 			break;
1813*4882a593Smuzhiyun 
1814*4882a593Smuzhiyun 		case NAND_OP_DATA_IN_INSTR:
1815*4882a593Smuzhiyun 		case NAND_OP_DATA_OUT_INSTR:
1816*4882a593Smuzhiyun 			start = nand_subop_get_data_start_off(subop, i);
1817*4882a593Smuzhiyun 			remaining = nand_subop_get_data_len(subop, i);
1818*4882a593Smuzhiyun 			cnt = min_t(u32, remaining, NFC_SRAM_SIZE);
1819*4882a593Smuzhiyun 			cmd |= NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD;
1820*4882a593Smuzhiyun 
1821*4882a593Smuzhiyun 			if (instr->type == NAND_OP_DATA_OUT_INSTR) {
1822*4882a593Smuzhiyun 				cmd |= NFC_ACCESS_DIR;
1823*4882a593Smuzhiyun 				memcpy_toio(nfc->regs + NFC_RAM0_BASE,
1824*4882a593Smuzhiyun 					    instr->ctx.data.buf.out + start,
1825*4882a593Smuzhiyun 					    cnt);
1826*4882a593Smuzhiyun 			} else {
1827*4882a593Smuzhiyun 				inbuf = instr->ctx.data.buf.in + start;
1828*4882a593Smuzhiyun 			}
1829*4882a593Smuzhiyun 
1830*4882a593Smuzhiyun 			break;
1831*4882a593Smuzhiyun 
1832*4882a593Smuzhiyun 		case NAND_OP_WAITRDY_INSTR:
1833*4882a593Smuzhiyun 			cmd |= NFC_WAIT_FLAG;
1834*4882a593Smuzhiyun 			break;
1835*4882a593Smuzhiyun 		}
1836*4882a593Smuzhiyun 	}
1837*4882a593Smuzhiyun 
1838*4882a593Smuzhiyun 	ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
1839*4882a593Smuzhiyun 	if (ret)
1840*4882a593Smuzhiyun 		return ret;
1841*4882a593Smuzhiyun 
1842*4882a593Smuzhiyun 	if (cmd & NFC_SEND_ADR) {
1843*4882a593Smuzhiyun 		writel(addrs[0], nfc->regs + NFC_REG_ADDR_LOW);
1844*4882a593Smuzhiyun 		writel(addrs[1], nfc->regs + NFC_REG_ADDR_HIGH);
1845*4882a593Smuzhiyun 	}
1846*4882a593Smuzhiyun 
1847*4882a593Smuzhiyun 	if (cmd & NFC_SEND_CMD2)
1848*4882a593Smuzhiyun 		writel(extcmd,
1849*4882a593Smuzhiyun 		       nfc->regs +
1850*4882a593Smuzhiyun 		       (cmd & NFC_ACCESS_DIR ?
1851*4882a593Smuzhiyun 			NFC_REG_WCMD_SET : NFC_REG_RCMD_SET));
1852*4882a593Smuzhiyun 
1853*4882a593Smuzhiyun 	if (cmd & NFC_DATA_TRANS)
1854*4882a593Smuzhiyun 		writel(cnt, nfc->regs + NFC_REG_CNT);
1855*4882a593Smuzhiyun 
1856*4882a593Smuzhiyun 	writel(cmd, nfc->regs + NFC_REG_CMD);
1857*4882a593Smuzhiyun 
1858*4882a593Smuzhiyun 	ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG,
1859*4882a593Smuzhiyun 				    !(cmd & NFC_WAIT_FLAG) && cnt < 64,
1860*4882a593Smuzhiyun 				    0);
1861*4882a593Smuzhiyun 	if (ret)
1862*4882a593Smuzhiyun 		return ret;
1863*4882a593Smuzhiyun 
1864*4882a593Smuzhiyun 	if (inbuf)
1865*4882a593Smuzhiyun 		memcpy_fromio(inbuf, nfc->regs + NFC_RAM0_BASE, cnt);
1866*4882a593Smuzhiyun 
1867*4882a593Smuzhiyun 	return 0;
1868*4882a593Smuzhiyun }
1869*4882a593Smuzhiyun 
sunxi_nfc_soft_waitrdy(struct nand_chip * nand,const struct nand_subop * subop)1870*4882a593Smuzhiyun static int sunxi_nfc_soft_waitrdy(struct nand_chip *nand,
1871*4882a593Smuzhiyun 				  const struct nand_subop *subop)
1872*4882a593Smuzhiyun {
1873*4882a593Smuzhiyun 	return nand_soft_waitrdy(nand,
1874*4882a593Smuzhiyun 				 subop->instrs[0].ctx.waitrdy.timeout_ms);
1875*4882a593Smuzhiyun }
1876*4882a593Smuzhiyun 
1877*4882a593Smuzhiyun static const struct nand_op_parser sunxi_nfc_op_parser = NAND_OP_PARSER(
1878*4882a593Smuzhiyun 	NAND_OP_PARSER_PATTERN(sunxi_nfc_exec_subop,
1879*4882a593Smuzhiyun 			       NAND_OP_PARSER_PAT_CMD_ELEM(true),
1880*4882a593Smuzhiyun 			       NAND_OP_PARSER_PAT_ADDR_ELEM(true, 8),
1881*4882a593Smuzhiyun 			       NAND_OP_PARSER_PAT_CMD_ELEM(true),
1882*4882a593Smuzhiyun 			       NAND_OP_PARSER_PAT_WAITRDY_ELEM(true),
1883*4882a593Smuzhiyun 			       NAND_OP_PARSER_PAT_DATA_IN_ELEM(true, 1024)),
1884*4882a593Smuzhiyun 	NAND_OP_PARSER_PATTERN(sunxi_nfc_exec_subop,
1885*4882a593Smuzhiyun 			       NAND_OP_PARSER_PAT_CMD_ELEM(true),
1886*4882a593Smuzhiyun 			       NAND_OP_PARSER_PAT_ADDR_ELEM(true, 8),
1887*4882a593Smuzhiyun 			       NAND_OP_PARSER_PAT_DATA_OUT_ELEM(true, 1024),
1888*4882a593Smuzhiyun 			       NAND_OP_PARSER_PAT_CMD_ELEM(true),
1889*4882a593Smuzhiyun 			       NAND_OP_PARSER_PAT_WAITRDY_ELEM(true)),
1890*4882a593Smuzhiyun );
1891*4882a593Smuzhiyun 
1892*4882a593Smuzhiyun static const struct nand_op_parser sunxi_nfc_norb_op_parser = NAND_OP_PARSER(
1893*4882a593Smuzhiyun 	NAND_OP_PARSER_PATTERN(sunxi_nfc_exec_subop,
1894*4882a593Smuzhiyun 			       NAND_OP_PARSER_PAT_CMD_ELEM(true),
1895*4882a593Smuzhiyun 			       NAND_OP_PARSER_PAT_ADDR_ELEM(true, 8),
1896*4882a593Smuzhiyun 			       NAND_OP_PARSER_PAT_CMD_ELEM(true),
1897*4882a593Smuzhiyun 			       NAND_OP_PARSER_PAT_DATA_IN_ELEM(true, 1024)),
1898*4882a593Smuzhiyun 	NAND_OP_PARSER_PATTERN(sunxi_nfc_exec_subop,
1899*4882a593Smuzhiyun 			       NAND_OP_PARSER_PAT_CMD_ELEM(true),
1900*4882a593Smuzhiyun 			       NAND_OP_PARSER_PAT_ADDR_ELEM(true, 8),
1901*4882a593Smuzhiyun 			       NAND_OP_PARSER_PAT_DATA_OUT_ELEM(true, 1024),
1902*4882a593Smuzhiyun 			       NAND_OP_PARSER_PAT_CMD_ELEM(true)),
1903*4882a593Smuzhiyun 	NAND_OP_PARSER_PATTERN(sunxi_nfc_soft_waitrdy,
1904*4882a593Smuzhiyun 			       NAND_OP_PARSER_PAT_WAITRDY_ELEM(false)),
1905*4882a593Smuzhiyun );
1906*4882a593Smuzhiyun 
sunxi_nfc_exec_op(struct nand_chip * nand,const struct nand_operation * op,bool check_only)1907*4882a593Smuzhiyun static int sunxi_nfc_exec_op(struct nand_chip *nand,
1908*4882a593Smuzhiyun 			     const struct nand_operation *op, bool check_only)
1909*4882a593Smuzhiyun {
1910*4882a593Smuzhiyun 	struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
1911*4882a593Smuzhiyun 	const struct nand_op_parser *parser;
1912*4882a593Smuzhiyun 
1913*4882a593Smuzhiyun 	if (!check_only)
1914*4882a593Smuzhiyun 		sunxi_nfc_select_chip(nand, op->cs);
1915*4882a593Smuzhiyun 
1916*4882a593Smuzhiyun 	if (sunxi_nand->sels[op->cs].rb >= 0)
1917*4882a593Smuzhiyun 		parser = &sunxi_nfc_op_parser;
1918*4882a593Smuzhiyun 	else
1919*4882a593Smuzhiyun 		parser = &sunxi_nfc_norb_op_parser;
1920*4882a593Smuzhiyun 
1921*4882a593Smuzhiyun 	return nand_op_parser_exec_op(nand, parser, op, check_only);
1922*4882a593Smuzhiyun }
1923*4882a593Smuzhiyun 
1924*4882a593Smuzhiyun static const struct nand_controller_ops sunxi_nand_controller_ops = {
1925*4882a593Smuzhiyun 	.attach_chip = sunxi_nand_attach_chip,
1926*4882a593Smuzhiyun 	.setup_interface = sunxi_nfc_setup_interface,
1927*4882a593Smuzhiyun 	.exec_op = sunxi_nfc_exec_op,
1928*4882a593Smuzhiyun };
1929*4882a593Smuzhiyun 
sunxi_nand_chip_init(struct device * dev,struct sunxi_nfc * nfc,struct device_node * np)1930*4882a593Smuzhiyun static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
1931*4882a593Smuzhiyun 				struct device_node *np)
1932*4882a593Smuzhiyun {
1933*4882a593Smuzhiyun 	struct sunxi_nand_chip *sunxi_nand;
1934*4882a593Smuzhiyun 	struct mtd_info *mtd;
1935*4882a593Smuzhiyun 	struct nand_chip *nand;
1936*4882a593Smuzhiyun 	int nsels;
1937*4882a593Smuzhiyun 	int ret;
1938*4882a593Smuzhiyun 	int i;
1939*4882a593Smuzhiyun 	u32 tmp;
1940*4882a593Smuzhiyun 
1941*4882a593Smuzhiyun 	if (!of_get_property(np, "reg", &nsels))
1942*4882a593Smuzhiyun 		return -EINVAL;
1943*4882a593Smuzhiyun 
1944*4882a593Smuzhiyun 	nsels /= sizeof(u32);
1945*4882a593Smuzhiyun 	if (!nsels) {
1946*4882a593Smuzhiyun 		dev_err(dev, "invalid reg property size\n");
1947*4882a593Smuzhiyun 		return -EINVAL;
1948*4882a593Smuzhiyun 	}
1949*4882a593Smuzhiyun 
1950*4882a593Smuzhiyun 	sunxi_nand = devm_kzalloc(dev, struct_size(sunxi_nand, sels, nsels),
1951*4882a593Smuzhiyun 				  GFP_KERNEL);
1952*4882a593Smuzhiyun 	if (!sunxi_nand) {
1953*4882a593Smuzhiyun 		dev_err(dev, "could not allocate chip\n");
1954*4882a593Smuzhiyun 		return -ENOMEM;
1955*4882a593Smuzhiyun 	}
1956*4882a593Smuzhiyun 
1957*4882a593Smuzhiyun 	sunxi_nand->nsels = nsels;
1958*4882a593Smuzhiyun 
1959*4882a593Smuzhiyun 	for (i = 0; i < nsels; i++) {
1960*4882a593Smuzhiyun 		ret = of_property_read_u32_index(np, "reg", i, &tmp);
1961*4882a593Smuzhiyun 		if (ret) {
1962*4882a593Smuzhiyun 			dev_err(dev, "could not retrieve reg property: %d\n",
1963*4882a593Smuzhiyun 				ret);
1964*4882a593Smuzhiyun 			return ret;
1965*4882a593Smuzhiyun 		}
1966*4882a593Smuzhiyun 
1967*4882a593Smuzhiyun 		if (tmp > NFC_MAX_CS) {
1968*4882a593Smuzhiyun 			dev_err(dev,
1969*4882a593Smuzhiyun 				"invalid reg value: %u (max CS = 7)\n",
1970*4882a593Smuzhiyun 				tmp);
1971*4882a593Smuzhiyun 			return -EINVAL;
1972*4882a593Smuzhiyun 		}
1973*4882a593Smuzhiyun 
1974*4882a593Smuzhiyun 		if (test_and_set_bit(tmp, &nfc->assigned_cs)) {
1975*4882a593Smuzhiyun 			dev_err(dev, "CS %d already assigned\n", tmp);
1976*4882a593Smuzhiyun 			return -EINVAL;
1977*4882a593Smuzhiyun 		}
1978*4882a593Smuzhiyun 
1979*4882a593Smuzhiyun 		sunxi_nand->sels[i].cs = tmp;
1980*4882a593Smuzhiyun 
1981*4882a593Smuzhiyun 		if (!of_property_read_u32_index(np, "allwinner,rb", i, &tmp) &&
1982*4882a593Smuzhiyun 		    tmp < 2)
1983*4882a593Smuzhiyun 			sunxi_nand->sels[i].rb = tmp;
1984*4882a593Smuzhiyun 		else
1985*4882a593Smuzhiyun 			sunxi_nand->sels[i].rb = -1;
1986*4882a593Smuzhiyun 	}
1987*4882a593Smuzhiyun 
1988*4882a593Smuzhiyun 	nand = &sunxi_nand->nand;
1989*4882a593Smuzhiyun 	/* Default tR value specified in the ONFI spec (chapter 4.15.1) */
1990*4882a593Smuzhiyun 	nand->controller = &nfc->controller;
1991*4882a593Smuzhiyun 	nand->controller->ops = &sunxi_nand_controller_ops;
1992*4882a593Smuzhiyun 
1993*4882a593Smuzhiyun 	/*
1994*4882a593Smuzhiyun 	 * Set the ECC mode to the default value in case nothing is specified
1995*4882a593Smuzhiyun 	 * in the DT.
1996*4882a593Smuzhiyun 	 */
1997*4882a593Smuzhiyun 	nand->ecc.engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST;
1998*4882a593Smuzhiyun 	nand_set_flash_node(nand, np);
1999*4882a593Smuzhiyun 
2000*4882a593Smuzhiyun 	mtd = nand_to_mtd(nand);
2001*4882a593Smuzhiyun 	mtd->dev.parent = dev;
2002*4882a593Smuzhiyun 
2003*4882a593Smuzhiyun 	ret = nand_scan(nand, nsels);
2004*4882a593Smuzhiyun 	if (ret)
2005*4882a593Smuzhiyun 		return ret;
2006*4882a593Smuzhiyun 
2007*4882a593Smuzhiyun 	ret = mtd_device_register(mtd, NULL, 0);
2008*4882a593Smuzhiyun 	if (ret) {
2009*4882a593Smuzhiyun 		dev_err(dev, "failed to register mtd device: %d\n", ret);
2010*4882a593Smuzhiyun 		nand_cleanup(nand);
2011*4882a593Smuzhiyun 		return ret;
2012*4882a593Smuzhiyun 	}
2013*4882a593Smuzhiyun 
2014*4882a593Smuzhiyun 	list_add_tail(&sunxi_nand->node, &nfc->chips);
2015*4882a593Smuzhiyun 
2016*4882a593Smuzhiyun 	return 0;
2017*4882a593Smuzhiyun }
2018*4882a593Smuzhiyun 
sunxi_nand_chips_init(struct device * dev,struct sunxi_nfc * nfc)2019*4882a593Smuzhiyun static int sunxi_nand_chips_init(struct device *dev, struct sunxi_nfc *nfc)
2020*4882a593Smuzhiyun {
2021*4882a593Smuzhiyun 	struct device_node *np = dev->of_node;
2022*4882a593Smuzhiyun 	struct device_node *nand_np;
2023*4882a593Smuzhiyun 	int nchips = of_get_child_count(np);
2024*4882a593Smuzhiyun 	int ret;
2025*4882a593Smuzhiyun 
2026*4882a593Smuzhiyun 	if (nchips > 8) {
2027*4882a593Smuzhiyun 		dev_err(dev, "too many NAND chips: %d (max = 8)\n", nchips);
2028*4882a593Smuzhiyun 		return -EINVAL;
2029*4882a593Smuzhiyun 	}
2030*4882a593Smuzhiyun 
2031*4882a593Smuzhiyun 	for_each_child_of_node(np, nand_np) {
2032*4882a593Smuzhiyun 		ret = sunxi_nand_chip_init(dev, nfc, nand_np);
2033*4882a593Smuzhiyun 		if (ret) {
2034*4882a593Smuzhiyun 			of_node_put(nand_np);
2035*4882a593Smuzhiyun 			return ret;
2036*4882a593Smuzhiyun 		}
2037*4882a593Smuzhiyun 	}
2038*4882a593Smuzhiyun 
2039*4882a593Smuzhiyun 	return 0;
2040*4882a593Smuzhiyun }
2041*4882a593Smuzhiyun 
sunxi_nand_chips_cleanup(struct sunxi_nfc * nfc)2042*4882a593Smuzhiyun static void sunxi_nand_chips_cleanup(struct sunxi_nfc *nfc)
2043*4882a593Smuzhiyun {
2044*4882a593Smuzhiyun 	struct sunxi_nand_chip *sunxi_nand;
2045*4882a593Smuzhiyun 	struct nand_chip *chip;
2046*4882a593Smuzhiyun 	int ret;
2047*4882a593Smuzhiyun 
2048*4882a593Smuzhiyun 	while (!list_empty(&nfc->chips)) {
2049*4882a593Smuzhiyun 		sunxi_nand = list_first_entry(&nfc->chips,
2050*4882a593Smuzhiyun 					      struct sunxi_nand_chip,
2051*4882a593Smuzhiyun 					      node);
2052*4882a593Smuzhiyun 		chip = &sunxi_nand->nand;
2053*4882a593Smuzhiyun 		ret = mtd_device_unregister(nand_to_mtd(chip));
2054*4882a593Smuzhiyun 		WARN_ON(ret);
2055*4882a593Smuzhiyun 		nand_cleanup(chip);
2056*4882a593Smuzhiyun 		sunxi_nand_ecc_cleanup(&chip->ecc);
2057*4882a593Smuzhiyun 		list_del(&sunxi_nand->node);
2058*4882a593Smuzhiyun 	}
2059*4882a593Smuzhiyun }
2060*4882a593Smuzhiyun 
sunxi_nfc_probe(struct platform_device * pdev)2061*4882a593Smuzhiyun static int sunxi_nfc_probe(struct platform_device *pdev)
2062*4882a593Smuzhiyun {
2063*4882a593Smuzhiyun 	struct device *dev = &pdev->dev;
2064*4882a593Smuzhiyun 	struct resource *r;
2065*4882a593Smuzhiyun 	struct sunxi_nfc *nfc;
2066*4882a593Smuzhiyun 	int irq;
2067*4882a593Smuzhiyun 	int ret;
2068*4882a593Smuzhiyun 
2069*4882a593Smuzhiyun 	nfc = devm_kzalloc(dev, sizeof(*nfc), GFP_KERNEL);
2070*4882a593Smuzhiyun 	if (!nfc)
2071*4882a593Smuzhiyun 		return -ENOMEM;
2072*4882a593Smuzhiyun 
2073*4882a593Smuzhiyun 	nfc->dev = dev;
2074*4882a593Smuzhiyun 	nand_controller_init(&nfc->controller);
2075*4882a593Smuzhiyun 	INIT_LIST_HEAD(&nfc->chips);
2076*4882a593Smuzhiyun 
2077*4882a593Smuzhiyun 	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
2078*4882a593Smuzhiyun 	nfc->regs = devm_ioremap_resource(dev, r);
2079*4882a593Smuzhiyun 	if (IS_ERR(nfc->regs))
2080*4882a593Smuzhiyun 		return PTR_ERR(nfc->regs);
2081*4882a593Smuzhiyun 
2082*4882a593Smuzhiyun 	irq = platform_get_irq(pdev, 0);
2083*4882a593Smuzhiyun 	if (irq < 0)
2084*4882a593Smuzhiyun 		return irq;
2085*4882a593Smuzhiyun 
2086*4882a593Smuzhiyun 	nfc->ahb_clk = devm_clk_get(dev, "ahb");
2087*4882a593Smuzhiyun 	if (IS_ERR(nfc->ahb_clk)) {
2088*4882a593Smuzhiyun 		dev_err(dev, "failed to retrieve ahb clk\n");
2089*4882a593Smuzhiyun 		return PTR_ERR(nfc->ahb_clk);
2090*4882a593Smuzhiyun 	}
2091*4882a593Smuzhiyun 
2092*4882a593Smuzhiyun 	ret = clk_prepare_enable(nfc->ahb_clk);
2093*4882a593Smuzhiyun 	if (ret)
2094*4882a593Smuzhiyun 		return ret;
2095*4882a593Smuzhiyun 
2096*4882a593Smuzhiyun 	nfc->mod_clk = devm_clk_get(dev, "mod");
2097*4882a593Smuzhiyun 	if (IS_ERR(nfc->mod_clk)) {
2098*4882a593Smuzhiyun 		dev_err(dev, "failed to retrieve mod clk\n");
2099*4882a593Smuzhiyun 		ret = PTR_ERR(nfc->mod_clk);
2100*4882a593Smuzhiyun 		goto out_ahb_clk_unprepare;
2101*4882a593Smuzhiyun 	}
2102*4882a593Smuzhiyun 
2103*4882a593Smuzhiyun 	ret = clk_prepare_enable(nfc->mod_clk);
2104*4882a593Smuzhiyun 	if (ret)
2105*4882a593Smuzhiyun 		goto out_ahb_clk_unprepare;
2106*4882a593Smuzhiyun 
2107*4882a593Smuzhiyun 	nfc->reset = devm_reset_control_get_optional_exclusive(dev, "ahb");
2108*4882a593Smuzhiyun 	if (IS_ERR(nfc->reset)) {
2109*4882a593Smuzhiyun 		ret = PTR_ERR(nfc->reset);
2110*4882a593Smuzhiyun 		goto out_mod_clk_unprepare;
2111*4882a593Smuzhiyun 	}
2112*4882a593Smuzhiyun 
2113*4882a593Smuzhiyun 	ret = reset_control_deassert(nfc->reset);
2114*4882a593Smuzhiyun 	if (ret) {
2115*4882a593Smuzhiyun 		dev_err(dev, "reset err %d\n", ret);
2116*4882a593Smuzhiyun 		goto out_mod_clk_unprepare;
2117*4882a593Smuzhiyun 	}
2118*4882a593Smuzhiyun 
2119*4882a593Smuzhiyun 	nfc->caps = of_device_get_match_data(&pdev->dev);
2120*4882a593Smuzhiyun 	if (!nfc->caps) {
2121*4882a593Smuzhiyun 		ret = -EINVAL;
2122*4882a593Smuzhiyun 		goto out_ahb_reset_reassert;
2123*4882a593Smuzhiyun 	}
2124*4882a593Smuzhiyun 
2125*4882a593Smuzhiyun 	ret = sunxi_nfc_rst(nfc);
2126*4882a593Smuzhiyun 	if (ret)
2127*4882a593Smuzhiyun 		goto out_ahb_reset_reassert;
2128*4882a593Smuzhiyun 
2129*4882a593Smuzhiyun 	writel(0, nfc->regs + NFC_REG_INT);
2130*4882a593Smuzhiyun 	ret = devm_request_irq(dev, irq, sunxi_nfc_interrupt,
2131*4882a593Smuzhiyun 			       0, "sunxi-nand", nfc);
2132*4882a593Smuzhiyun 	if (ret)
2133*4882a593Smuzhiyun 		goto out_ahb_reset_reassert;
2134*4882a593Smuzhiyun 
2135*4882a593Smuzhiyun 	nfc->dmac = dma_request_chan(dev, "rxtx");
2136*4882a593Smuzhiyun 	if (IS_ERR(nfc->dmac)) {
2137*4882a593Smuzhiyun 		ret = PTR_ERR(nfc->dmac);
2138*4882a593Smuzhiyun 		if (ret == -EPROBE_DEFER)
2139*4882a593Smuzhiyun 			goto out_ahb_reset_reassert;
2140*4882a593Smuzhiyun 
2141*4882a593Smuzhiyun 		/* Ignore errors to fall back to PIO mode */
2142*4882a593Smuzhiyun 		dev_warn(dev, "failed to request rxtx DMA channel: %d\n", ret);
2143*4882a593Smuzhiyun 		nfc->dmac = NULL;
2144*4882a593Smuzhiyun 	} else {
2145*4882a593Smuzhiyun 		struct dma_slave_config dmac_cfg = { };
2146*4882a593Smuzhiyun 
2147*4882a593Smuzhiyun 		dmac_cfg.src_addr = r->start + nfc->caps->reg_io_data;
2148*4882a593Smuzhiyun 		dmac_cfg.dst_addr = dmac_cfg.src_addr;
2149*4882a593Smuzhiyun 		dmac_cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
2150*4882a593Smuzhiyun 		dmac_cfg.dst_addr_width = dmac_cfg.src_addr_width;
2151*4882a593Smuzhiyun 		dmac_cfg.src_maxburst = nfc->caps->dma_maxburst;
2152*4882a593Smuzhiyun 		dmac_cfg.dst_maxburst = nfc->caps->dma_maxburst;
2153*4882a593Smuzhiyun 		dmaengine_slave_config(nfc->dmac, &dmac_cfg);
2154*4882a593Smuzhiyun 
2155*4882a593Smuzhiyun 		if (nfc->caps->extra_mbus_conf)
2156*4882a593Smuzhiyun 			writel(readl(nfc->regs + NFC_REG_CTL) |
2157*4882a593Smuzhiyun 			       NFC_DMA_TYPE_NORMAL, nfc->regs + NFC_REG_CTL);
2158*4882a593Smuzhiyun 	}
2159*4882a593Smuzhiyun 
2160*4882a593Smuzhiyun 	platform_set_drvdata(pdev, nfc);
2161*4882a593Smuzhiyun 
2162*4882a593Smuzhiyun 	ret = sunxi_nand_chips_init(dev, nfc);
2163*4882a593Smuzhiyun 	if (ret) {
2164*4882a593Smuzhiyun 		dev_err(dev, "failed to init nand chips\n");
2165*4882a593Smuzhiyun 		goto out_release_dmac;
2166*4882a593Smuzhiyun 	}
2167*4882a593Smuzhiyun 
2168*4882a593Smuzhiyun 	return 0;
2169*4882a593Smuzhiyun 
2170*4882a593Smuzhiyun out_release_dmac:
2171*4882a593Smuzhiyun 	if (nfc->dmac)
2172*4882a593Smuzhiyun 		dma_release_channel(nfc->dmac);
2173*4882a593Smuzhiyun out_ahb_reset_reassert:
2174*4882a593Smuzhiyun 	reset_control_assert(nfc->reset);
2175*4882a593Smuzhiyun out_mod_clk_unprepare:
2176*4882a593Smuzhiyun 	clk_disable_unprepare(nfc->mod_clk);
2177*4882a593Smuzhiyun out_ahb_clk_unprepare:
2178*4882a593Smuzhiyun 	clk_disable_unprepare(nfc->ahb_clk);
2179*4882a593Smuzhiyun 
2180*4882a593Smuzhiyun 	return ret;
2181*4882a593Smuzhiyun }
2182*4882a593Smuzhiyun 
sunxi_nfc_remove(struct platform_device * pdev)2183*4882a593Smuzhiyun static int sunxi_nfc_remove(struct platform_device *pdev)
2184*4882a593Smuzhiyun {
2185*4882a593Smuzhiyun 	struct sunxi_nfc *nfc = platform_get_drvdata(pdev);
2186*4882a593Smuzhiyun 
2187*4882a593Smuzhiyun 	sunxi_nand_chips_cleanup(nfc);
2188*4882a593Smuzhiyun 
2189*4882a593Smuzhiyun 	reset_control_assert(nfc->reset);
2190*4882a593Smuzhiyun 
2191*4882a593Smuzhiyun 	if (nfc->dmac)
2192*4882a593Smuzhiyun 		dma_release_channel(nfc->dmac);
2193*4882a593Smuzhiyun 	clk_disable_unprepare(nfc->mod_clk);
2194*4882a593Smuzhiyun 	clk_disable_unprepare(nfc->ahb_clk);
2195*4882a593Smuzhiyun 
2196*4882a593Smuzhiyun 	return 0;
2197*4882a593Smuzhiyun }
2198*4882a593Smuzhiyun 
2199*4882a593Smuzhiyun static const struct sunxi_nfc_caps sunxi_nfc_a10_caps = {
2200*4882a593Smuzhiyun 	.reg_io_data = NFC_REG_A10_IO_DATA,
2201*4882a593Smuzhiyun 	.dma_maxburst = 4,
2202*4882a593Smuzhiyun };
2203*4882a593Smuzhiyun 
2204*4882a593Smuzhiyun static const struct sunxi_nfc_caps sunxi_nfc_a23_caps = {
2205*4882a593Smuzhiyun 	.extra_mbus_conf = true,
2206*4882a593Smuzhiyun 	.reg_io_data = NFC_REG_A23_IO_DATA,
2207*4882a593Smuzhiyun 	.dma_maxburst = 8,
2208*4882a593Smuzhiyun };
2209*4882a593Smuzhiyun 
2210*4882a593Smuzhiyun static const struct of_device_id sunxi_nfc_ids[] = {
2211*4882a593Smuzhiyun 	{
2212*4882a593Smuzhiyun 		.compatible = "allwinner,sun4i-a10-nand",
2213*4882a593Smuzhiyun 		.data = &sunxi_nfc_a10_caps,
2214*4882a593Smuzhiyun 	},
2215*4882a593Smuzhiyun 	{
2216*4882a593Smuzhiyun 		.compatible = "allwinner,sun8i-a23-nand-controller",
2217*4882a593Smuzhiyun 		.data = &sunxi_nfc_a23_caps,
2218*4882a593Smuzhiyun 	},
2219*4882a593Smuzhiyun 	{ /* sentinel */ }
2220*4882a593Smuzhiyun };
2221*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, sunxi_nfc_ids);
2222*4882a593Smuzhiyun 
2223*4882a593Smuzhiyun static struct platform_driver sunxi_nfc_driver = {
2224*4882a593Smuzhiyun 	.driver = {
2225*4882a593Smuzhiyun 		.name = "sunxi_nand",
2226*4882a593Smuzhiyun 		.of_match_table = sunxi_nfc_ids,
2227*4882a593Smuzhiyun 	},
2228*4882a593Smuzhiyun 	.probe = sunxi_nfc_probe,
2229*4882a593Smuzhiyun 	.remove = sunxi_nfc_remove,
2230*4882a593Smuzhiyun };
2231*4882a593Smuzhiyun module_platform_driver(sunxi_nfc_driver);
2232*4882a593Smuzhiyun 
2233*4882a593Smuzhiyun MODULE_LICENSE("GPL");
2234*4882a593Smuzhiyun MODULE_AUTHOR("Boris BREZILLON");
2235*4882a593Smuzhiyun MODULE_DESCRIPTION("Allwinner NAND Flash Controller driver");
2236*4882a593Smuzhiyun MODULE_ALIAS("platform:sunxi_nand");
2237