xref: /OK3568_Linux_fs/u-boot/drivers/mtd/nand/raw/arasan_nfc.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Arasan NAND Flash Controller Driver
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Copyright (C) 2014 - 2015 Xilinx, Inc.
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * SPDX-License-Identifier:     GPL-2.0+
7*4882a593Smuzhiyun  */
8*4882a593Smuzhiyun 
9*4882a593Smuzhiyun #include <common.h>
10*4882a593Smuzhiyun #include <malloc.h>
11*4882a593Smuzhiyun #include <asm/io.h>
12*4882a593Smuzhiyun #include <linux/errno.h>
13*4882a593Smuzhiyun #include <linux/mtd/mtd.h>
14*4882a593Smuzhiyun #include <linux/mtd/rawnand.h>
15*4882a593Smuzhiyun #include <linux/mtd/partitions.h>
16*4882a593Smuzhiyun #include <linux/mtd/nand_ecc.h>
17*4882a593Smuzhiyun #include <asm/arch/hardware.h>
18*4882a593Smuzhiyun #include <asm/arch/sys_proto.h>
19*4882a593Smuzhiyun #include <nand.h>
20*4882a593Smuzhiyun 
21*4882a593Smuzhiyun struct arasan_nand_info {
22*4882a593Smuzhiyun 	void __iomem *nand_base;
23*4882a593Smuzhiyun 	u32 page;
24*4882a593Smuzhiyun 	bool on_die_ecc_enabled;
25*4882a593Smuzhiyun };
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun struct nand_regs {
28*4882a593Smuzhiyun 	u32 pkt_reg;
29*4882a593Smuzhiyun 	u32 memadr_reg1;
30*4882a593Smuzhiyun 	u32 memadr_reg2;
31*4882a593Smuzhiyun 	u32 cmd_reg;
32*4882a593Smuzhiyun 	u32 pgm_reg;
33*4882a593Smuzhiyun 	u32 intsts_enr;
34*4882a593Smuzhiyun 	u32 intsig_enr;
35*4882a593Smuzhiyun 	u32 intsts_reg;
36*4882a593Smuzhiyun 	u32 rdy_busy;
37*4882a593Smuzhiyun 	u32 cms_sysadr_reg;
38*4882a593Smuzhiyun 	u32 flash_sts_reg;
39*4882a593Smuzhiyun 	u32 tmg_reg;
40*4882a593Smuzhiyun 	u32 buf_dataport;
41*4882a593Smuzhiyun 	u32 ecc_reg;
42*4882a593Smuzhiyun 	u32 ecc_errcnt_reg;
43*4882a593Smuzhiyun 	u32 ecc_sprcmd_reg;
44*4882a593Smuzhiyun 	u32 errcnt_1bitreg;
45*4882a593Smuzhiyun 	u32 errcnt_2bitreg;
46*4882a593Smuzhiyun 	u32 errcnt_3bitreg;
47*4882a593Smuzhiyun 	u32 errcnt_4bitreg;
48*4882a593Smuzhiyun 	u32 dma_sysadr0_reg;
49*4882a593Smuzhiyun 	u32 dma_bufbdry_reg;
50*4882a593Smuzhiyun 	u32 cpu_rls_reg;
51*4882a593Smuzhiyun 	u32 errcnt_5bitreg;
52*4882a593Smuzhiyun 	u32 errcnt_6bitreg;
53*4882a593Smuzhiyun 	u32 errcnt_7bitreg;
54*4882a593Smuzhiyun 	u32 errcnt_8bitreg;
55*4882a593Smuzhiyun 	u32 data_if_reg;
56*4882a593Smuzhiyun };
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun #define arasan_nand_base ((struct nand_regs __iomem *)ARASAN_NAND_BASEADDR)
59*4882a593Smuzhiyun 
60*4882a593Smuzhiyun struct arasan_nand_command_format {
61*4882a593Smuzhiyun 	u8 cmd1;
62*4882a593Smuzhiyun 	u8 cmd2;
63*4882a593Smuzhiyun 	u8 addr_cycles;
64*4882a593Smuzhiyun 	u32 pgm;
65*4882a593Smuzhiyun };
66*4882a593Smuzhiyun 
67*4882a593Smuzhiyun #define ONDIE_ECC_FEATURE_ADDR			0x90
68*4882a593Smuzhiyun #define ENABLE_ONDIE_ECC			0x08
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun #define ARASAN_PROG_RD_MASK			0x00000001
71*4882a593Smuzhiyun #define ARASAN_PROG_BLK_ERS_MASK		0x00000004
72*4882a593Smuzhiyun #define ARASAN_PROG_RD_ID_MASK			0x00000040
73*4882a593Smuzhiyun #define ARASAN_PROG_RD_STS_MASK			0x00000008
74*4882a593Smuzhiyun #define ARASAN_PROG_PG_PROG_MASK		0x00000010
75*4882a593Smuzhiyun #define ARASAN_PROG_RD_PARAM_PG_MASK		0x00000080
76*4882a593Smuzhiyun #define ARASAN_PROG_RST_MASK			0x00000100
77*4882a593Smuzhiyun #define ARASAN_PROG_GET_FTRS_MASK		0x00000200
78*4882a593Smuzhiyun #define ARASAN_PROG_SET_FTRS_MASK		0x00000400
79*4882a593Smuzhiyun #define ARASAN_PROG_CHNG_ROWADR_END_MASK	0x00400000
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun #define ARASAN_NAND_CMD_ECC_ON_MASK		0x80000000
82*4882a593Smuzhiyun #define ARASAN_NAND_CMD_CMD12_MASK		0xFFFF
83*4882a593Smuzhiyun #define ARASAN_NAND_CMD_PG_SIZE_MASK		0x3800000
84*4882a593Smuzhiyun #define ARASAN_NAND_CMD_PG_SIZE_SHIFT		23
85*4882a593Smuzhiyun #define ARASAN_NAND_CMD_CMD2_SHIFT		8
86*4882a593Smuzhiyun #define ARASAN_NAND_CMD_ADDR_CYCL_MASK		0x70000000
87*4882a593Smuzhiyun #define ARASAN_NAND_CMD_ADDR_CYCL_SHIFT		28
88*4882a593Smuzhiyun 
89*4882a593Smuzhiyun #define ARASAN_NAND_MEM_ADDR1_PAGE_MASK		0xFFFF0000
90*4882a593Smuzhiyun #define ARASAN_NAND_MEM_ADDR1_COL_MASK		0xFFFF
91*4882a593Smuzhiyun #define ARASAN_NAND_MEM_ADDR1_PAGE_SHIFT	16
92*4882a593Smuzhiyun #define ARASAN_NAND_MEM_ADDR2_PAGE_MASK		0xFF
93*4882a593Smuzhiyun #define ARASAN_NAND_MEM_ADDR2_CS_MASK		0xC0000000
94*4882a593Smuzhiyun #define ARASAN_NAND_MEM_ADDR2_CS0_MASK         (0x3 << 30)
95*4882a593Smuzhiyun #define ARASAN_NAND_MEM_ADDR2_CS1_MASK         (0x1 << 30)
96*4882a593Smuzhiyun #define ARASAN_NAND_MEM_ADDR2_BCH_MASK		0xE000000
97*4882a593Smuzhiyun #define ARASAN_NAND_MEM_ADDR2_BCH_SHIFT		25
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun #define ARASAN_NAND_INT_STS_ERR_EN_MASK		0x10
100*4882a593Smuzhiyun #define ARASAN_NAND_INT_STS_MUL_BIT_ERR_MASK	0x08
101*4882a593Smuzhiyun #define ARASAN_NAND_INT_STS_BUF_RD_RDY_MASK	0x02
102*4882a593Smuzhiyun #define ARASAN_NAND_INT_STS_BUF_WR_RDY_MASK	0x01
103*4882a593Smuzhiyun #define ARASAN_NAND_INT_STS_XFR_CMPLT_MASK	0x04
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun #define ARASAN_NAND_PKT_REG_PKT_CNT_MASK	0xFFF000
106*4882a593Smuzhiyun #define ARASAN_NAND_PKT_REG_PKT_SIZE_MASK	0x7FF
107*4882a593Smuzhiyun #define ARASAN_NAND_PKT_REG_PKT_CNT_SHFT	12
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun #define ARASAN_NAND_ROW_ADDR_CYCL_MASK		0x0F
110*4882a593Smuzhiyun #define ARASAN_NAND_COL_ADDR_CYCL_MASK		0xF0
111*4882a593Smuzhiyun #define ARASAN_NAND_COL_ADDR_CYCL_SHIFT		4
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun #define ARASAN_NAND_ECC_SIZE_SHIFT		16
114*4882a593Smuzhiyun #define ARASAN_NAND_ECC_BCH_SHIFT		27
115*4882a593Smuzhiyun 
116*4882a593Smuzhiyun #define ARASAN_NAND_PKTSIZE_1K			1024
117*4882a593Smuzhiyun #define ARASAN_NAND_PKTSIZE_512			512
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun #define ARASAN_NAND_POLL_TIMEOUT		1000000
120*4882a593Smuzhiyun #define ARASAN_NAND_INVALID_ADDR_CYCL		0xFF
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun #define ERR_ADDR_CYCLE				-1
123*4882a593Smuzhiyun #define READ_BUFF_SIZE				0x4000
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun static struct arasan_nand_command_format *curr_cmd;
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun enum addr_cycles {
128*4882a593Smuzhiyun 	NAND_ADDR_CYCL_NONE,
129*4882a593Smuzhiyun 	NAND_ADDR_CYCL_ONE,
130*4882a593Smuzhiyun 	NAND_ADDR_CYCL_ROW,
131*4882a593Smuzhiyun 	NAND_ADDR_CYCL_COL,
132*4882a593Smuzhiyun 	NAND_ADDR_CYCL_BOTH,
133*4882a593Smuzhiyun };
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun static struct arasan_nand_command_format arasan_nand_commands[] = {
136*4882a593Smuzhiyun 	{NAND_CMD_READ0, NAND_CMD_READSTART, NAND_ADDR_CYCL_BOTH,
137*4882a593Smuzhiyun 	 ARASAN_PROG_RD_MASK},
138*4882a593Smuzhiyun 	{NAND_CMD_RNDOUT, NAND_CMD_RNDOUTSTART, NAND_ADDR_CYCL_COL,
139*4882a593Smuzhiyun 	 ARASAN_PROG_RD_MASK},
140*4882a593Smuzhiyun 	{NAND_CMD_READID, NAND_CMD_NONE, NAND_ADDR_CYCL_ONE,
141*4882a593Smuzhiyun 	 ARASAN_PROG_RD_ID_MASK},
142*4882a593Smuzhiyun 	{NAND_CMD_STATUS, NAND_CMD_NONE, NAND_ADDR_CYCL_NONE,
143*4882a593Smuzhiyun 	 ARASAN_PROG_RD_STS_MASK},
144*4882a593Smuzhiyun 	{NAND_CMD_SEQIN, NAND_CMD_PAGEPROG, NAND_ADDR_CYCL_BOTH,
145*4882a593Smuzhiyun 	 ARASAN_PROG_PG_PROG_MASK},
146*4882a593Smuzhiyun 	{NAND_CMD_RNDIN, NAND_CMD_NONE, NAND_ADDR_CYCL_COL,
147*4882a593Smuzhiyun 	 ARASAN_PROG_CHNG_ROWADR_END_MASK},
148*4882a593Smuzhiyun 	{NAND_CMD_ERASE1, NAND_CMD_ERASE2, NAND_ADDR_CYCL_ROW,
149*4882a593Smuzhiyun 	 ARASAN_PROG_BLK_ERS_MASK},
150*4882a593Smuzhiyun 	{NAND_CMD_RESET, NAND_CMD_NONE, NAND_ADDR_CYCL_NONE,
151*4882a593Smuzhiyun 	 ARASAN_PROG_RST_MASK},
152*4882a593Smuzhiyun 	{NAND_CMD_PARAM, NAND_CMD_NONE, NAND_ADDR_CYCL_ONE,
153*4882a593Smuzhiyun 	 ARASAN_PROG_RD_PARAM_PG_MASK},
154*4882a593Smuzhiyun 	{NAND_CMD_GET_FEATURES, NAND_CMD_NONE, NAND_ADDR_CYCL_ONE,
155*4882a593Smuzhiyun 	 ARASAN_PROG_GET_FTRS_MASK},
156*4882a593Smuzhiyun 	{NAND_CMD_SET_FEATURES, NAND_CMD_NONE, NAND_ADDR_CYCL_ONE,
157*4882a593Smuzhiyun 	 ARASAN_PROG_SET_FTRS_MASK},
158*4882a593Smuzhiyun 	{NAND_CMD_NONE, NAND_CMD_NONE, NAND_ADDR_CYCL_NONE, 0},
159*4882a593Smuzhiyun };
160*4882a593Smuzhiyun 
161*4882a593Smuzhiyun struct arasan_ecc_matrix {
162*4882a593Smuzhiyun 	u32 pagesize;
163*4882a593Smuzhiyun 	u32 ecc_codeword_size;
164*4882a593Smuzhiyun 	u8 eccbits;
165*4882a593Smuzhiyun 	u8 bch;
166*4882a593Smuzhiyun 	u8 bchval;
167*4882a593Smuzhiyun 	u16 eccaddr;
168*4882a593Smuzhiyun 	u16 eccsize;
169*4882a593Smuzhiyun };
170*4882a593Smuzhiyun 
171*4882a593Smuzhiyun static const struct arasan_ecc_matrix ecc_matrix[] = {
172*4882a593Smuzhiyun 	{512, 512, 1, 0, 0, 0x20D, 0x3},
173*4882a593Smuzhiyun 	{512, 512, 4, 1, 3, 0x209, 0x7},
174*4882a593Smuzhiyun 	{512, 512, 8, 1, 2, 0x203, 0xD},
175*4882a593Smuzhiyun 	/*
176*4882a593Smuzhiyun 	 * 2K byte page
177*4882a593Smuzhiyun 	 */
178*4882a593Smuzhiyun 	{2048, 512, 1, 0, 0, 0x834, 0xC},
179*4882a593Smuzhiyun 	{2048, 512, 4, 1, 3, 0x826, 0x1A},
180*4882a593Smuzhiyun 	{2048, 512, 8, 1, 2, 0x80c, 0x34},
181*4882a593Smuzhiyun 	{2048, 512, 12, 1, 1, 0x822, 0x4E},
182*4882a593Smuzhiyun 	{2048, 512, 16, 1, 0, 0x808, 0x68},
183*4882a593Smuzhiyun 	{2048, 1024, 24, 1, 4, 0x81c, 0x54},
184*4882a593Smuzhiyun 	/*
185*4882a593Smuzhiyun 	 * 4K byte page
186*4882a593Smuzhiyun 	 */
187*4882a593Smuzhiyun 	{4096, 512, 1, 0, 0, 0x1068, 0x18},
188*4882a593Smuzhiyun 	{4096, 512, 4, 1, 3, 0x104c, 0x34},
189*4882a593Smuzhiyun 	{4096, 512, 8, 1, 2, 0x1018, 0x68},
190*4882a593Smuzhiyun 	{4096, 512, 12, 1, 1, 0x1044, 0x9C},
191*4882a593Smuzhiyun 	{4096, 512, 16, 1, 0, 0x1010, 0xD0},
192*4882a593Smuzhiyun 	{4096, 1024, 24, 1, 4, 0x1038, 0xA8},
193*4882a593Smuzhiyun 	/*
194*4882a593Smuzhiyun 	 * 8K byte page
195*4882a593Smuzhiyun 	 */
196*4882a593Smuzhiyun 	{8192, 512, 1, 0, 0, 0x20d0, 0x30},
197*4882a593Smuzhiyun 	{8192, 512, 4, 1, 3, 0x2098, 0x68},
198*4882a593Smuzhiyun 	{8192, 512, 8, 1, 2, 0x2030, 0xD0},
199*4882a593Smuzhiyun 	{8192, 512, 12, 1, 1, 0x2088, 0x138},
200*4882a593Smuzhiyun 	{8192, 512, 16, 1, 0, 0x2020, 0x1A0},
201*4882a593Smuzhiyun 	{8192, 1024, 24, 1, 4, 0x2070, 0x150},
202*4882a593Smuzhiyun 	/*
203*4882a593Smuzhiyun 	 * 16K byte page
204*4882a593Smuzhiyun 	 */
205*4882a593Smuzhiyun 	{16384, 512, 1, 0, 0, 0x4460, 0x60},
206*4882a593Smuzhiyun 	{16384, 512, 4, 1, 3, 0x43f0, 0xD0},
207*4882a593Smuzhiyun 	{16384, 512, 8, 1, 2, 0x4320, 0x1A0},
208*4882a593Smuzhiyun 	{16384, 512, 12, 1, 1, 0x4250, 0x270},
209*4882a593Smuzhiyun 	{16384, 512, 16, 1, 0, 0x4180, 0x340},
210*4882a593Smuzhiyun 	{16384, 1024, 24, 1, 4, 0x4220, 0x2A0}
211*4882a593Smuzhiyun };
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun static struct nand_ecclayout ondie_nand_oob_64 = {
214*4882a593Smuzhiyun 	.eccbytes = 32,
215*4882a593Smuzhiyun 
216*4882a593Smuzhiyun 	.eccpos = {
217*4882a593Smuzhiyun 		8, 9, 10, 11, 12, 13, 14, 15,
218*4882a593Smuzhiyun 		24, 25, 26, 27, 28, 29, 30, 31,
219*4882a593Smuzhiyun 		40, 41, 42, 43, 44, 45, 46, 47,
220*4882a593Smuzhiyun 		56, 57, 58, 59, 60, 61, 62, 63
221*4882a593Smuzhiyun 	},
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun 	.oobfree = {
224*4882a593Smuzhiyun 		{ .offset = 4, .length = 4 },
225*4882a593Smuzhiyun 		{ .offset = 20, .length = 4 },
226*4882a593Smuzhiyun 		{ .offset = 36, .length = 4 },
227*4882a593Smuzhiyun 		{ .offset = 52, .length = 4 }
228*4882a593Smuzhiyun 	}
229*4882a593Smuzhiyun };
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun /*
232*4882a593Smuzhiyun  * bbt decriptors for chips with on-die ECC and
233*4882a593Smuzhiyun  * chips with 64-byte OOB
234*4882a593Smuzhiyun  */
235*4882a593Smuzhiyun static u8 bbt_pattern[] = {'B', 'b', 't', '0' };
236*4882a593Smuzhiyun static u8 mirror_pattern[] = {'1', 't', 'b', 'B' };
237*4882a593Smuzhiyun 
238*4882a593Smuzhiyun static struct nand_bbt_descr bbt_main_descr = {
239*4882a593Smuzhiyun 	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE |
240*4882a593Smuzhiyun 		NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
241*4882a593Smuzhiyun 	.offs = 4,
242*4882a593Smuzhiyun 	.len = 4,
243*4882a593Smuzhiyun 	.veroffs = 20,
244*4882a593Smuzhiyun 	.maxblocks = 4,
245*4882a593Smuzhiyun 	.pattern = bbt_pattern
246*4882a593Smuzhiyun };
247*4882a593Smuzhiyun 
248*4882a593Smuzhiyun static struct nand_bbt_descr bbt_mirror_descr = {
249*4882a593Smuzhiyun 	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE |
250*4882a593Smuzhiyun 		NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
251*4882a593Smuzhiyun 	.offs = 4,
252*4882a593Smuzhiyun 	.len = 4,
253*4882a593Smuzhiyun 	.veroffs = 20,
254*4882a593Smuzhiyun 	.maxblocks = 4,
255*4882a593Smuzhiyun 	.pattern = mirror_pattern
256*4882a593Smuzhiyun };
257*4882a593Smuzhiyun 
258*4882a593Smuzhiyun static u8 buf_data[READ_BUFF_SIZE];
259*4882a593Smuzhiyun static u32 buf_index;
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun static struct nand_ecclayout nand_oob;
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun static struct nand_chip nand_chip[CONFIG_SYS_MAX_NAND_DEVICE];
264*4882a593Smuzhiyun 
arasan_nand_select_chip(struct mtd_info * mtd,int chip)265*4882a593Smuzhiyun static void arasan_nand_select_chip(struct mtd_info *mtd, int chip)
266*4882a593Smuzhiyun {
267*4882a593Smuzhiyun 	u32 reg_val;
268*4882a593Smuzhiyun 
269*4882a593Smuzhiyun 	reg_val = readl(&arasan_nand_base->memadr_reg2);
270*4882a593Smuzhiyun 	if (chip == 0) {
271*4882a593Smuzhiyun 		reg_val &= ~ARASAN_NAND_MEM_ADDR2_CS0_MASK;
272*4882a593Smuzhiyun 		writel(reg_val, &arasan_nand_base->memadr_reg2);
273*4882a593Smuzhiyun 	} else if (chip == 1) {
274*4882a593Smuzhiyun 		reg_val |= ARASAN_NAND_MEM_ADDR2_CS1_MASK;
275*4882a593Smuzhiyun 		writel(reg_val, &arasan_nand_base->memadr_reg2);
276*4882a593Smuzhiyun 	}
277*4882a593Smuzhiyun }
278*4882a593Smuzhiyun 
arasan_nand_enable_ecc(void)279*4882a593Smuzhiyun static void arasan_nand_enable_ecc(void)
280*4882a593Smuzhiyun {
281*4882a593Smuzhiyun 	u32 reg_val;
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun 	reg_val = readl(&arasan_nand_base->cmd_reg);
284*4882a593Smuzhiyun 	reg_val |= ARASAN_NAND_CMD_ECC_ON_MASK;
285*4882a593Smuzhiyun 
286*4882a593Smuzhiyun 	writel(reg_val, &arasan_nand_base->cmd_reg);
287*4882a593Smuzhiyun }
288*4882a593Smuzhiyun 
arasan_nand_get_addrcycle(struct mtd_info * mtd)289*4882a593Smuzhiyun static u8 arasan_nand_get_addrcycle(struct mtd_info *mtd)
290*4882a593Smuzhiyun {
291*4882a593Smuzhiyun 	u8 addrcycles;
292*4882a593Smuzhiyun 	struct nand_chip *chip = mtd_to_nand(mtd);
293*4882a593Smuzhiyun 
294*4882a593Smuzhiyun 	switch (curr_cmd->addr_cycles) {
295*4882a593Smuzhiyun 	case NAND_ADDR_CYCL_NONE:
296*4882a593Smuzhiyun 		addrcycles = 0;
297*4882a593Smuzhiyun 		break;
298*4882a593Smuzhiyun 	case NAND_ADDR_CYCL_ONE:
299*4882a593Smuzhiyun 		addrcycles = 1;
300*4882a593Smuzhiyun 		break;
301*4882a593Smuzhiyun 	case NAND_ADDR_CYCL_ROW:
302*4882a593Smuzhiyun 		addrcycles = chip->onfi_params.addr_cycles &
303*4882a593Smuzhiyun 			     ARASAN_NAND_ROW_ADDR_CYCL_MASK;
304*4882a593Smuzhiyun 		break;
305*4882a593Smuzhiyun 	case NAND_ADDR_CYCL_COL:
306*4882a593Smuzhiyun 		addrcycles = (chip->onfi_params.addr_cycles &
307*4882a593Smuzhiyun 			      ARASAN_NAND_COL_ADDR_CYCL_MASK) >>
308*4882a593Smuzhiyun 			      ARASAN_NAND_COL_ADDR_CYCL_SHIFT;
309*4882a593Smuzhiyun 		break;
310*4882a593Smuzhiyun 	case NAND_ADDR_CYCL_BOTH:
311*4882a593Smuzhiyun 		addrcycles = chip->onfi_params.addr_cycles &
312*4882a593Smuzhiyun 			     ARASAN_NAND_ROW_ADDR_CYCL_MASK;
313*4882a593Smuzhiyun 		addrcycles += (chip->onfi_params.addr_cycles &
314*4882a593Smuzhiyun 			       ARASAN_NAND_COL_ADDR_CYCL_MASK) >>
315*4882a593Smuzhiyun 			       ARASAN_NAND_COL_ADDR_CYCL_SHIFT;
316*4882a593Smuzhiyun 		break;
317*4882a593Smuzhiyun 	default:
318*4882a593Smuzhiyun 		addrcycles = ARASAN_NAND_INVALID_ADDR_CYCL;
319*4882a593Smuzhiyun 		break;
320*4882a593Smuzhiyun 	}
321*4882a593Smuzhiyun 	return addrcycles;
322*4882a593Smuzhiyun }
323*4882a593Smuzhiyun 
arasan_nand_read_page(struct mtd_info * mtd,u8 * buf,u32 size)324*4882a593Smuzhiyun static int arasan_nand_read_page(struct mtd_info *mtd, u8 *buf, u32 size)
325*4882a593Smuzhiyun {
326*4882a593Smuzhiyun 	struct nand_chip *chip = mtd_to_nand(mtd);
327*4882a593Smuzhiyun 	struct arasan_nand_info *nand = nand_get_controller_data(chip);
328*4882a593Smuzhiyun 	u32 reg_val, i, pktsize, pktnum;
329*4882a593Smuzhiyun 	u32 *bufptr = (u32 *)buf;
330*4882a593Smuzhiyun 	u32 timeout;
331*4882a593Smuzhiyun 	u32  rdcount = 0;
332*4882a593Smuzhiyun 	u8 addr_cycles;
333*4882a593Smuzhiyun 
334*4882a593Smuzhiyun 	if (chip->ecc_step_ds >= ARASAN_NAND_PKTSIZE_1K)
335*4882a593Smuzhiyun 		pktsize = ARASAN_NAND_PKTSIZE_1K;
336*4882a593Smuzhiyun 	else
337*4882a593Smuzhiyun 		pktsize = ARASAN_NAND_PKTSIZE_512;
338*4882a593Smuzhiyun 
339*4882a593Smuzhiyun 	if (size % pktsize)
340*4882a593Smuzhiyun 		pktnum = size/pktsize + 1;
341*4882a593Smuzhiyun 	else
342*4882a593Smuzhiyun 		pktnum = size/pktsize;
343*4882a593Smuzhiyun 
344*4882a593Smuzhiyun 	reg_val = readl(&arasan_nand_base->intsts_enr);
345*4882a593Smuzhiyun 	reg_val |= ARASAN_NAND_INT_STS_ERR_EN_MASK |
346*4882a593Smuzhiyun 		   ARASAN_NAND_INT_STS_MUL_BIT_ERR_MASK;
347*4882a593Smuzhiyun 	writel(reg_val, &arasan_nand_base->intsts_enr);
348*4882a593Smuzhiyun 
349*4882a593Smuzhiyun 	reg_val = readl(&arasan_nand_base->pkt_reg);
350*4882a593Smuzhiyun 	reg_val &= ~(ARASAN_NAND_PKT_REG_PKT_CNT_MASK |
351*4882a593Smuzhiyun 		     ARASAN_NAND_PKT_REG_PKT_SIZE_MASK);
352*4882a593Smuzhiyun 	reg_val |= (pktnum << ARASAN_NAND_PKT_REG_PKT_CNT_SHFT) |
353*4882a593Smuzhiyun 		    pktsize;
354*4882a593Smuzhiyun 	writel(reg_val, &arasan_nand_base->pkt_reg);
355*4882a593Smuzhiyun 
356*4882a593Smuzhiyun 	if (!nand->on_die_ecc_enabled) {
357*4882a593Smuzhiyun 		arasan_nand_enable_ecc();
358*4882a593Smuzhiyun 		addr_cycles = arasan_nand_get_addrcycle(mtd);
359*4882a593Smuzhiyun 		if (addr_cycles == ARASAN_NAND_INVALID_ADDR_CYCL)
360*4882a593Smuzhiyun 			return ERR_ADDR_CYCLE;
361*4882a593Smuzhiyun 
362*4882a593Smuzhiyun 		writel((NAND_CMD_RNDOUTSTART << ARASAN_NAND_CMD_CMD2_SHIFT) |
363*4882a593Smuzhiyun 		       NAND_CMD_RNDOUT | (addr_cycles <<
364*4882a593Smuzhiyun 		       ARASAN_NAND_CMD_ADDR_CYCL_SHIFT),
365*4882a593Smuzhiyun 		       &arasan_nand_base->ecc_sprcmd_reg);
366*4882a593Smuzhiyun 	}
367*4882a593Smuzhiyun 	writel(curr_cmd->pgm, &arasan_nand_base->pgm_reg);
368*4882a593Smuzhiyun 
369*4882a593Smuzhiyun 	while (rdcount < pktnum) {
370*4882a593Smuzhiyun 		timeout = ARASAN_NAND_POLL_TIMEOUT;
371*4882a593Smuzhiyun 		while (!(readl(&arasan_nand_base->intsts_reg) &
372*4882a593Smuzhiyun 			ARASAN_NAND_INT_STS_BUF_RD_RDY_MASK) && timeout) {
373*4882a593Smuzhiyun 			udelay(1);
374*4882a593Smuzhiyun 			timeout--;
375*4882a593Smuzhiyun 		}
376*4882a593Smuzhiyun 		if (!timeout) {
377*4882a593Smuzhiyun 			puts("arasan_read_page: timedout:Buff RDY\n");
378*4882a593Smuzhiyun 			return -ETIMEDOUT;
379*4882a593Smuzhiyun 		}
380*4882a593Smuzhiyun 
381*4882a593Smuzhiyun 		rdcount++;
382*4882a593Smuzhiyun 
383*4882a593Smuzhiyun 		if (pktnum == rdcount) {
384*4882a593Smuzhiyun 			reg_val = readl(&arasan_nand_base->intsts_enr);
385*4882a593Smuzhiyun 			reg_val |= ARASAN_NAND_INT_STS_XFR_CMPLT_MASK;
386*4882a593Smuzhiyun 			writel(reg_val, &arasan_nand_base->intsts_enr);
387*4882a593Smuzhiyun 		} else {
388*4882a593Smuzhiyun 			reg_val = readl(&arasan_nand_base->intsts_enr);
389*4882a593Smuzhiyun 			writel(reg_val | ARASAN_NAND_INT_STS_BUF_RD_RDY_MASK,
390*4882a593Smuzhiyun 			       &arasan_nand_base->intsts_enr);
391*4882a593Smuzhiyun 		}
392*4882a593Smuzhiyun 		reg_val = readl(&arasan_nand_base->intsts_reg);
393*4882a593Smuzhiyun 		writel(reg_val | ARASAN_NAND_INT_STS_BUF_RD_RDY_MASK,
394*4882a593Smuzhiyun 		       &arasan_nand_base->intsts_reg);
395*4882a593Smuzhiyun 
396*4882a593Smuzhiyun 		for (i = 0; i < pktsize/4; i++)
397*4882a593Smuzhiyun 			bufptr[i] = readl(&arasan_nand_base->buf_dataport);
398*4882a593Smuzhiyun 
399*4882a593Smuzhiyun 
400*4882a593Smuzhiyun 		bufptr += pktsize/4;
401*4882a593Smuzhiyun 
402*4882a593Smuzhiyun 		if (rdcount >= pktnum)
403*4882a593Smuzhiyun 			break;
404*4882a593Smuzhiyun 
405*4882a593Smuzhiyun 		writel(ARASAN_NAND_INT_STS_BUF_RD_RDY_MASK,
406*4882a593Smuzhiyun 		       &arasan_nand_base->intsts_enr);
407*4882a593Smuzhiyun 	}
408*4882a593Smuzhiyun 
409*4882a593Smuzhiyun 	timeout = ARASAN_NAND_POLL_TIMEOUT;
410*4882a593Smuzhiyun 
411*4882a593Smuzhiyun 	while (!(readl(&arasan_nand_base->intsts_reg) &
412*4882a593Smuzhiyun 		ARASAN_NAND_INT_STS_XFR_CMPLT_MASK) && timeout) {
413*4882a593Smuzhiyun 		udelay(1);
414*4882a593Smuzhiyun 		timeout--;
415*4882a593Smuzhiyun 	}
416*4882a593Smuzhiyun 	if (!timeout) {
417*4882a593Smuzhiyun 		puts("arasan rd_page timedout:Xfer CMPLT\n");
418*4882a593Smuzhiyun 		return -ETIMEDOUT;
419*4882a593Smuzhiyun 	}
420*4882a593Smuzhiyun 
421*4882a593Smuzhiyun 	reg_val = readl(&arasan_nand_base->intsts_enr);
422*4882a593Smuzhiyun 	writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
423*4882a593Smuzhiyun 	       &arasan_nand_base->intsts_enr);
424*4882a593Smuzhiyun 	reg_val = readl(&arasan_nand_base->intsts_reg);
425*4882a593Smuzhiyun 	writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
426*4882a593Smuzhiyun 	       &arasan_nand_base->intsts_reg);
427*4882a593Smuzhiyun 
428*4882a593Smuzhiyun 	if (!nand->on_die_ecc_enabled) {
429*4882a593Smuzhiyun 		if (readl(&arasan_nand_base->intsts_reg) &
430*4882a593Smuzhiyun 		    ARASAN_NAND_INT_STS_MUL_BIT_ERR_MASK) {
431*4882a593Smuzhiyun 			printf("arasan rd_page:sbiterror\n");
432*4882a593Smuzhiyun 			return -1;
433*4882a593Smuzhiyun 		}
434*4882a593Smuzhiyun 
435*4882a593Smuzhiyun 		if (readl(&arasan_nand_base->intsts_reg) &
436*4882a593Smuzhiyun 		    ARASAN_NAND_INT_STS_ERR_EN_MASK) {
437*4882a593Smuzhiyun 			mtd->ecc_stats.failed++;
438*4882a593Smuzhiyun 			printf("arasan rd_page:multibiterror\n");
439*4882a593Smuzhiyun 			return -1;
440*4882a593Smuzhiyun 		}
441*4882a593Smuzhiyun 	}
442*4882a593Smuzhiyun 
443*4882a593Smuzhiyun 	return 0;
444*4882a593Smuzhiyun }
445*4882a593Smuzhiyun 
arasan_nand_read_page_hwecc(struct mtd_info * mtd,struct nand_chip * chip,u8 * buf,int oob_required,int page)446*4882a593Smuzhiyun static int arasan_nand_read_page_hwecc(struct mtd_info *mtd,
447*4882a593Smuzhiyun 		struct nand_chip *chip, u8 *buf, int oob_required, int page)
448*4882a593Smuzhiyun {
449*4882a593Smuzhiyun 	int status;
450*4882a593Smuzhiyun 
451*4882a593Smuzhiyun 	status = arasan_nand_read_page(mtd, buf, (mtd->writesize));
452*4882a593Smuzhiyun 
453*4882a593Smuzhiyun 	if (oob_required)
454*4882a593Smuzhiyun 		chip->ecc.read_oob(mtd, chip, page);
455*4882a593Smuzhiyun 
456*4882a593Smuzhiyun 	return status;
457*4882a593Smuzhiyun }
458*4882a593Smuzhiyun 
arasan_nand_fill_tx(const u8 * buf,int len)459*4882a593Smuzhiyun static void arasan_nand_fill_tx(const u8 *buf, int len)
460*4882a593Smuzhiyun {
461*4882a593Smuzhiyun 	u32 __iomem *nand = &arasan_nand_base->buf_dataport;
462*4882a593Smuzhiyun 
463*4882a593Smuzhiyun 	if (((unsigned long)buf & 0x3) != 0) {
464*4882a593Smuzhiyun 		if (((unsigned long)buf & 0x1) != 0) {
465*4882a593Smuzhiyun 			if (len) {
466*4882a593Smuzhiyun 				writeb(*buf, nand);
467*4882a593Smuzhiyun 				buf += 1;
468*4882a593Smuzhiyun 				len--;
469*4882a593Smuzhiyun 			}
470*4882a593Smuzhiyun 		}
471*4882a593Smuzhiyun 
472*4882a593Smuzhiyun 		if (((unsigned long)buf & 0x3) != 0) {
473*4882a593Smuzhiyun 			if (len >= 2) {
474*4882a593Smuzhiyun 				writew(*(u16 *)buf, nand);
475*4882a593Smuzhiyun 				buf += 2;
476*4882a593Smuzhiyun 				len -= 2;
477*4882a593Smuzhiyun 			}
478*4882a593Smuzhiyun 		}
479*4882a593Smuzhiyun 	}
480*4882a593Smuzhiyun 
481*4882a593Smuzhiyun 	while (len >= 4) {
482*4882a593Smuzhiyun 		writel(*(u32 *)buf, nand);
483*4882a593Smuzhiyun 		buf += 4;
484*4882a593Smuzhiyun 		len -= 4;
485*4882a593Smuzhiyun 	}
486*4882a593Smuzhiyun 
487*4882a593Smuzhiyun 	if (len) {
488*4882a593Smuzhiyun 		if (len >= 2) {
489*4882a593Smuzhiyun 			writew(*(u16 *)buf, nand);
490*4882a593Smuzhiyun 			buf += 2;
491*4882a593Smuzhiyun 			len -= 2;
492*4882a593Smuzhiyun 		}
493*4882a593Smuzhiyun 
494*4882a593Smuzhiyun 		if (len)
495*4882a593Smuzhiyun 			writeb(*buf, nand);
496*4882a593Smuzhiyun 	}
497*4882a593Smuzhiyun }
498*4882a593Smuzhiyun 
arasan_nand_write_page_hwecc(struct mtd_info * mtd,struct nand_chip * chip,const u8 * buf,int oob_required,int page)499*4882a593Smuzhiyun static int arasan_nand_write_page_hwecc(struct mtd_info *mtd,
500*4882a593Smuzhiyun 		struct nand_chip *chip, const u8 *buf, int oob_required,
501*4882a593Smuzhiyun 		int page)
502*4882a593Smuzhiyun {
503*4882a593Smuzhiyun 	u32 reg_val, i, pktsize, pktnum;
504*4882a593Smuzhiyun 	const u32 *bufptr = (const u32 *)buf;
505*4882a593Smuzhiyun 	u32 timeout = ARASAN_NAND_POLL_TIMEOUT;
506*4882a593Smuzhiyun 	u32 size = mtd->writesize;
507*4882a593Smuzhiyun 	u32 rdcount = 0;
508*4882a593Smuzhiyun 	u8 column_addr_cycles;
509*4882a593Smuzhiyun 	struct arasan_nand_info *nand = nand_get_controller_data(chip);
510*4882a593Smuzhiyun 
511*4882a593Smuzhiyun 	if (chip->ecc_step_ds >= ARASAN_NAND_PKTSIZE_1K)
512*4882a593Smuzhiyun 		pktsize = ARASAN_NAND_PKTSIZE_1K;
513*4882a593Smuzhiyun 	else
514*4882a593Smuzhiyun 		pktsize = ARASAN_NAND_PKTSIZE_512;
515*4882a593Smuzhiyun 
516*4882a593Smuzhiyun 	if (size % pktsize)
517*4882a593Smuzhiyun 		pktnum = size/pktsize + 1;
518*4882a593Smuzhiyun 	else
519*4882a593Smuzhiyun 		pktnum = size/pktsize;
520*4882a593Smuzhiyun 
521*4882a593Smuzhiyun 	reg_val = readl(&arasan_nand_base->pkt_reg);
522*4882a593Smuzhiyun 	reg_val &= ~(ARASAN_NAND_PKT_REG_PKT_CNT_MASK |
523*4882a593Smuzhiyun 		     ARASAN_NAND_PKT_REG_PKT_SIZE_MASK);
524*4882a593Smuzhiyun 	reg_val |= (pktnum << ARASAN_NAND_PKT_REG_PKT_CNT_SHFT) | pktsize;
525*4882a593Smuzhiyun 	writel(reg_val, &arasan_nand_base->pkt_reg);
526*4882a593Smuzhiyun 
527*4882a593Smuzhiyun 	if (!nand->on_die_ecc_enabled) {
528*4882a593Smuzhiyun 		arasan_nand_enable_ecc();
529*4882a593Smuzhiyun 		column_addr_cycles = (chip->onfi_params.addr_cycles &
530*4882a593Smuzhiyun 				      ARASAN_NAND_COL_ADDR_CYCL_MASK) >>
531*4882a593Smuzhiyun 				      ARASAN_NAND_COL_ADDR_CYCL_SHIFT;
532*4882a593Smuzhiyun 		writel((NAND_CMD_RNDIN | (column_addr_cycles << 28)),
533*4882a593Smuzhiyun 		       &arasan_nand_base->ecc_sprcmd_reg);
534*4882a593Smuzhiyun 	}
535*4882a593Smuzhiyun 	writel(curr_cmd->pgm, &arasan_nand_base->pgm_reg);
536*4882a593Smuzhiyun 
537*4882a593Smuzhiyun 	while (rdcount < pktnum) {
538*4882a593Smuzhiyun 		timeout = ARASAN_NAND_POLL_TIMEOUT;
539*4882a593Smuzhiyun 		while (!(readl(&arasan_nand_base->intsts_reg) &
540*4882a593Smuzhiyun 			ARASAN_NAND_INT_STS_BUF_WR_RDY_MASK) && timeout) {
541*4882a593Smuzhiyun 			udelay(1);
542*4882a593Smuzhiyun 			timeout--;
543*4882a593Smuzhiyun 		}
544*4882a593Smuzhiyun 
545*4882a593Smuzhiyun 		if (!timeout) {
546*4882a593Smuzhiyun 			puts("arasan_write_page: timedout:Buff RDY\n");
547*4882a593Smuzhiyun 			return -ETIMEDOUT;
548*4882a593Smuzhiyun 		}
549*4882a593Smuzhiyun 
550*4882a593Smuzhiyun 		rdcount++;
551*4882a593Smuzhiyun 
552*4882a593Smuzhiyun 		if (pktnum == rdcount) {
553*4882a593Smuzhiyun 			reg_val = readl(&arasan_nand_base->intsts_enr);
554*4882a593Smuzhiyun 			reg_val |= ARASAN_NAND_INT_STS_XFR_CMPLT_MASK;
555*4882a593Smuzhiyun 			writel(reg_val, &arasan_nand_base->intsts_enr);
556*4882a593Smuzhiyun 		} else {
557*4882a593Smuzhiyun 			reg_val = readl(&arasan_nand_base->intsts_enr);
558*4882a593Smuzhiyun 			writel(reg_val | ARASAN_NAND_INT_STS_BUF_WR_RDY_MASK,
559*4882a593Smuzhiyun 			       &arasan_nand_base->intsts_enr);
560*4882a593Smuzhiyun 		}
561*4882a593Smuzhiyun 
562*4882a593Smuzhiyun 		reg_val = readl(&arasan_nand_base->intsts_reg);
563*4882a593Smuzhiyun 		writel(reg_val | ARASAN_NAND_INT_STS_BUF_WR_RDY_MASK,
564*4882a593Smuzhiyun 		       &arasan_nand_base->intsts_reg);
565*4882a593Smuzhiyun 
566*4882a593Smuzhiyun 		for (i = 0; i < pktsize/4; i++)
567*4882a593Smuzhiyun 			writel(bufptr[i], &arasan_nand_base->buf_dataport);
568*4882a593Smuzhiyun 
569*4882a593Smuzhiyun 		bufptr += pktsize/4;
570*4882a593Smuzhiyun 
571*4882a593Smuzhiyun 		if (rdcount >= pktnum)
572*4882a593Smuzhiyun 			break;
573*4882a593Smuzhiyun 
574*4882a593Smuzhiyun 		writel(ARASAN_NAND_INT_STS_BUF_WR_RDY_MASK,
575*4882a593Smuzhiyun 		       &arasan_nand_base->intsts_enr);
576*4882a593Smuzhiyun 	}
577*4882a593Smuzhiyun 
578*4882a593Smuzhiyun 	timeout = ARASAN_NAND_POLL_TIMEOUT;
579*4882a593Smuzhiyun 
580*4882a593Smuzhiyun 	while (!(readl(&arasan_nand_base->intsts_reg) &
581*4882a593Smuzhiyun 		ARASAN_NAND_INT_STS_XFR_CMPLT_MASK) && timeout) {
582*4882a593Smuzhiyun 		udelay(1);
583*4882a593Smuzhiyun 		timeout--;
584*4882a593Smuzhiyun 	}
585*4882a593Smuzhiyun 	if (!timeout) {
586*4882a593Smuzhiyun 		puts("arasan write_page timedout:Xfer CMPLT\n");
587*4882a593Smuzhiyun 		return -ETIMEDOUT;
588*4882a593Smuzhiyun 	}
589*4882a593Smuzhiyun 
590*4882a593Smuzhiyun 	reg_val = readl(&arasan_nand_base->intsts_enr);
591*4882a593Smuzhiyun 	writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
592*4882a593Smuzhiyun 	       &arasan_nand_base->intsts_enr);
593*4882a593Smuzhiyun 	reg_val = readl(&arasan_nand_base->intsts_reg);
594*4882a593Smuzhiyun 	writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
595*4882a593Smuzhiyun 	       &arasan_nand_base->intsts_reg);
596*4882a593Smuzhiyun 
597*4882a593Smuzhiyun 	if (oob_required)
598*4882a593Smuzhiyun 		chip->ecc.write_oob(mtd, chip, nand->page);
599*4882a593Smuzhiyun 
600*4882a593Smuzhiyun 	return 0;
601*4882a593Smuzhiyun }
602*4882a593Smuzhiyun 
arasan_nand_read_oob(struct mtd_info * mtd,struct nand_chip * chip,int page)603*4882a593Smuzhiyun static int arasan_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
604*4882a593Smuzhiyun 				int page)
605*4882a593Smuzhiyun {
606*4882a593Smuzhiyun 	chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
607*4882a593Smuzhiyun 	chip->read_buf(mtd, chip->oob_poi, (mtd->oobsize));
608*4882a593Smuzhiyun 
609*4882a593Smuzhiyun 	return 0;
610*4882a593Smuzhiyun }
611*4882a593Smuzhiyun 
arasan_nand_write_oob(struct mtd_info * mtd,struct nand_chip * chip,int page)612*4882a593Smuzhiyun static int arasan_nand_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
613*4882a593Smuzhiyun 				 int page)
614*4882a593Smuzhiyun {
615*4882a593Smuzhiyun 	int status = 0;
616*4882a593Smuzhiyun 	const u8 *buf = chip->oob_poi;
617*4882a593Smuzhiyun 
618*4882a593Smuzhiyun 	chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page);
619*4882a593Smuzhiyun 	chip->write_buf(mtd, buf, mtd->oobsize);
620*4882a593Smuzhiyun 
621*4882a593Smuzhiyun 	return status;
622*4882a593Smuzhiyun }
623*4882a593Smuzhiyun 
arasan_nand_reset(struct arasan_nand_command_format * curr_cmd)624*4882a593Smuzhiyun static int arasan_nand_reset(struct arasan_nand_command_format *curr_cmd)
625*4882a593Smuzhiyun {
626*4882a593Smuzhiyun 	u32 timeout = ARASAN_NAND_POLL_TIMEOUT;
627*4882a593Smuzhiyun 	u32 cmd_reg = 0;
628*4882a593Smuzhiyun 
629*4882a593Smuzhiyun 	writel(ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
630*4882a593Smuzhiyun 	       &arasan_nand_base->intsts_enr);
631*4882a593Smuzhiyun 	cmd_reg = readl(&arasan_nand_base->cmd_reg);
632*4882a593Smuzhiyun 	cmd_reg &= ~ARASAN_NAND_CMD_CMD12_MASK;
633*4882a593Smuzhiyun 
634*4882a593Smuzhiyun 	cmd_reg |= curr_cmd->cmd1 |
635*4882a593Smuzhiyun 		  (curr_cmd->cmd2 << ARASAN_NAND_CMD_CMD2_SHIFT);
636*4882a593Smuzhiyun 	writel(cmd_reg, &arasan_nand_base->cmd_reg);
637*4882a593Smuzhiyun 	writel(curr_cmd->pgm, &arasan_nand_base->pgm_reg);
638*4882a593Smuzhiyun 
639*4882a593Smuzhiyun 	while (!(readl(&arasan_nand_base->intsts_reg) &
640*4882a593Smuzhiyun 		ARASAN_NAND_INT_STS_XFR_CMPLT_MASK) && timeout) {
641*4882a593Smuzhiyun 		udelay(1);
642*4882a593Smuzhiyun 		timeout--;
643*4882a593Smuzhiyun 	}
644*4882a593Smuzhiyun 	if (!timeout) {
645*4882a593Smuzhiyun 		printf("ERROR:%s timedout\n", __func__);
646*4882a593Smuzhiyun 		return -ETIMEDOUT;
647*4882a593Smuzhiyun 	}
648*4882a593Smuzhiyun 
649*4882a593Smuzhiyun 	writel(ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
650*4882a593Smuzhiyun 	       &arasan_nand_base->intsts_enr);
651*4882a593Smuzhiyun 
652*4882a593Smuzhiyun 	writel(ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
653*4882a593Smuzhiyun 	       &arasan_nand_base->intsts_reg);
654*4882a593Smuzhiyun 
655*4882a593Smuzhiyun 	return 0;
656*4882a593Smuzhiyun }
657*4882a593Smuzhiyun 
arasan_nand_page(struct mtd_info * mtd)658*4882a593Smuzhiyun static u8 arasan_nand_page(struct mtd_info *mtd)
659*4882a593Smuzhiyun {
660*4882a593Smuzhiyun 	u8 page_val = 0;
661*4882a593Smuzhiyun 
662*4882a593Smuzhiyun 	switch (mtd->writesize) {
663*4882a593Smuzhiyun 	case 512:
664*4882a593Smuzhiyun 		page_val = 0;
665*4882a593Smuzhiyun 		break;
666*4882a593Smuzhiyun 	case 2048:
667*4882a593Smuzhiyun 		page_val = 1;
668*4882a593Smuzhiyun 		break;
669*4882a593Smuzhiyun 	case 4096:
670*4882a593Smuzhiyun 		page_val = 2;
671*4882a593Smuzhiyun 		break;
672*4882a593Smuzhiyun 	case 8192:
673*4882a593Smuzhiyun 		page_val = 3;
674*4882a593Smuzhiyun 		break;
675*4882a593Smuzhiyun 	case 16384:
676*4882a593Smuzhiyun 		page_val = 4;
677*4882a593Smuzhiyun 		break;
678*4882a593Smuzhiyun 	case 1024:
679*4882a593Smuzhiyun 		page_val = 5;
680*4882a593Smuzhiyun 		break;
681*4882a593Smuzhiyun 	default:
682*4882a593Smuzhiyun 		printf("%s:Pagesize>16K\n", __func__);
683*4882a593Smuzhiyun 		break;
684*4882a593Smuzhiyun 	}
685*4882a593Smuzhiyun 
686*4882a593Smuzhiyun 	return page_val;
687*4882a593Smuzhiyun }
688*4882a593Smuzhiyun 
arasan_nand_send_wrcmd(struct arasan_nand_command_format * curr_cmd,int column,int page_addr,struct mtd_info * mtd)689*4882a593Smuzhiyun static int arasan_nand_send_wrcmd(struct arasan_nand_command_format *curr_cmd,
690*4882a593Smuzhiyun 			int column, int page_addr, struct mtd_info *mtd)
691*4882a593Smuzhiyun {
692*4882a593Smuzhiyun 	u32 reg_val, page;
693*4882a593Smuzhiyun 	u8 page_val, addr_cycles;
694*4882a593Smuzhiyun 
695*4882a593Smuzhiyun 	writel(ARASAN_NAND_INT_STS_BUF_WR_RDY_MASK,
696*4882a593Smuzhiyun 	       &arasan_nand_base->intsts_enr);
697*4882a593Smuzhiyun 	reg_val = readl(&arasan_nand_base->cmd_reg);
698*4882a593Smuzhiyun 	reg_val &= ~ARASAN_NAND_CMD_CMD12_MASK;
699*4882a593Smuzhiyun 	reg_val |= curr_cmd->cmd1 |
700*4882a593Smuzhiyun 		   (curr_cmd->cmd2 << ARASAN_NAND_CMD_CMD2_SHIFT);
701*4882a593Smuzhiyun 	if (curr_cmd->cmd1 == NAND_CMD_SEQIN) {
702*4882a593Smuzhiyun 		reg_val &= ~ARASAN_NAND_CMD_PG_SIZE_MASK;
703*4882a593Smuzhiyun 		page_val = arasan_nand_page(mtd);
704*4882a593Smuzhiyun 		reg_val |= (page_val << ARASAN_NAND_CMD_PG_SIZE_SHIFT);
705*4882a593Smuzhiyun 	}
706*4882a593Smuzhiyun 
707*4882a593Smuzhiyun 	reg_val &= ~ARASAN_NAND_CMD_ADDR_CYCL_MASK;
708*4882a593Smuzhiyun 	addr_cycles = arasan_nand_get_addrcycle(mtd);
709*4882a593Smuzhiyun 
710*4882a593Smuzhiyun 	if (addr_cycles == ARASAN_NAND_INVALID_ADDR_CYCL)
711*4882a593Smuzhiyun 		return ERR_ADDR_CYCLE;
712*4882a593Smuzhiyun 
713*4882a593Smuzhiyun 	reg_val |= (addr_cycles <<
714*4882a593Smuzhiyun 		   ARASAN_NAND_CMD_ADDR_CYCL_SHIFT);
715*4882a593Smuzhiyun 	writel(reg_val, &arasan_nand_base->cmd_reg);
716*4882a593Smuzhiyun 
717*4882a593Smuzhiyun 	if (page_addr == -1)
718*4882a593Smuzhiyun 		page_addr = 0;
719*4882a593Smuzhiyun 
720*4882a593Smuzhiyun 	page = (page_addr << ARASAN_NAND_MEM_ADDR1_PAGE_SHIFT) &
721*4882a593Smuzhiyun 		ARASAN_NAND_MEM_ADDR1_PAGE_MASK;
722*4882a593Smuzhiyun 	column &= ARASAN_NAND_MEM_ADDR1_COL_MASK;
723*4882a593Smuzhiyun 	writel(page|column, &arasan_nand_base->memadr_reg1);
724*4882a593Smuzhiyun 
725*4882a593Smuzhiyun 	reg_val = readl(&arasan_nand_base->memadr_reg2);
726*4882a593Smuzhiyun 	reg_val &= ~ARASAN_NAND_MEM_ADDR2_PAGE_MASK;
727*4882a593Smuzhiyun 	reg_val |= (page_addr >> ARASAN_NAND_MEM_ADDR1_PAGE_SHIFT);
728*4882a593Smuzhiyun 	writel(reg_val, &arasan_nand_base->memadr_reg2);
729*4882a593Smuzhiyun 
730*4882a593Smuzhiyun 	return 0;
731*4882a593Smuzhiyun }
732*4882a593Smuzhiyun 
arasan_nand_write_buf(struct mtd_info * mtd,const u8 * buf,int len)733*4882a593Smuzhiyun static void arasan_nand_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
734*4882a593Smuzhiyun {
735*4882a593Smuzhiyun 	u32 reg_val;
736*4882a593Smuzhiyun 	u32 timeout = ARASAN_NAND_POLL_TIMEOUT;
737*4882a593Smuzhiyun 
738*4882a593Smuzhiyun 	reg_val = readl(&arasan_nand_base->pkt_reg);
739*4882a593Smuzhiyun 	reg_val &= ~(ARASAN_NAND_PKT_REG_PKT_CNT_MASK |
740*4882a593Smuzhiyun 		     ARASAN_NAND_PKT_REG_PKT_SIZE_MASK);
741*4882a593Smuzhiyun 
742*4882a593Smuzhiyun 	reg_val |= (1 << ARASAN_NAND_PKT_REG_PKT_CNT_SHFT) | len;
743*4882a593Smuzhiyun 	writel(reg_val, &arasan_nand_base->pkt_reg);
744*4882a593Smuzhiyun 	writel(curr_cmd->pgm, &arasan_nand_base->pgm_reg);
745*4882a593Smuzhiyun 
746*4882a593Smuzhiyun 	while (!(readl(&arasan_nand_base->intsts_reg) &
747*4882a593Smuzhiyun 		ARASAN_NAND_INT_STS_BUF_WR_RDY_MASK) && timeout) {
748*4882a593Smuzhiyun 		udelay(1);
749*4882a593Smuzhiyun 		timeout--;
750*4882a593Smuzhiyun 	}
751*4882a593Smuzhiyun 
752*4882a593Smuzhiyun 	if (!timeout)
753*4882a593Smuzhiyun 		puts("ERROR:arasan_nand_write_buf timedout:Buff RDY\n");
754*4882a593Smuzhiyun 
755*4882a593Smuzhiyun 	reg_val = readl(&arasan_nand_base->intsts_enr);
756*4882a593Smuzhiyun 	reg_val |= ARASAN_NAND_INT_STS_XFR_CMPLT_MASK;
757*4882a593Smuzhiyun 	writel(reg_val, &arasan_nand_base->intsts_enr);
758*4882a593Smuzhiyun 	writel(reg_val | ARASAN_NAND_INT_STS_BUF_WR_RDY_MASK,
759*4882a593Smuzhiyun 	       &arasan_nand_base->intsts_enr);
760*4882a593Smuzhiyun 	reg_val = readl(&arasan_nand_base->intsts_reg);
761*4882a593Smuzhiyun 	writel(reg_val | ARASAN_NAND_INT_STS_BUF_WR_RDY_MASK,
762*4882a593Smuzhiyun 	       &arasan_nand_base->intsts_reg);
763*4882a593Smuzhiyun 
764*4882a593Smuzhiyun 	arasan_nand_fill_tx(buf, len);
765*4882a593Smuzhiyun 
766*4882a593Smuzhiyun 	timeout = ARASAN_NAND_POLL_TIMEOUT;
767*4882a593Smuzhiyun 	while (!(readl(&arasan_nand_base->intsts_reg) &
768*4882a593Smuzhiyun 		ARASAN_NAND_INT_STS_XFR_CMPLT_MASK) && timeout) {
769*4882a593Smuzhiyun 		udelay(1);
770*4882a593Smuzhiyun 		timeout--;
771*4882a593Smuzhiyun 	}
772*4882a593Smuzhiyun 	if (!timeout)
773*4882a593Smuzhiyun 		puts("ERROR:arasan_nand_write_buf timedout:Xfer CMPLT\n");
774*4882a593Smuzhiyun 
775*4882a593Smuzhiyun 	writel(readl(&arasan_nand_base->intsts_enr) |
776*4882a593Smuzhiyun 	       ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
777*4882a593Smuzhiyun 	       &arasan_nand_base->intsts_enr);
778*4882a593Smuzhiyun 	writel(readl(&arasan_nand_base->intsts_reg) |
779*4882a593Smuzhiyun 	       ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
780*4882a593Smuzhiyun 	       &arasan_nand_base->intsts_reg);
781*4882a593Smuzhiyun }
782*4882a593Smuzhiyun 
arasan_nand_erase(struct arasan_nand_command_format * curr_cmd,int column,int page_addr,struct mtd_info * mtd)783*4882a593Smuzhiyun static int arasan_nand_erase(struct arasan_nand_command_format *curr_cmd,
784*4882a593Smuzhiyun 			      int column, int page_addr, struct mtd_info *mtd)
785*4882a593Smuzhiyun {
786*4882a593Smuzhiyun 	u32 reg_val, page;
787*4882a593Smuzhiyun 	u32 timeout = ARASAN_NAND_POLL_TIMEOUT;
788*4882a593Smuzhiyun 	u8 row_addr_cycles;
789*4882a593Smuzhiyun 
790*4882a593Smuzhiyun 	writel(ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
791*4882a593Smuzhiyun 	       &arasan_nand_base->intsts_enr);
792*4882a593Smuzhiyun 	reg_val = readl(&arasan_nand_base->cmd_reg);
793*4882a593Smuzhiyun 	reg_val &= ~ARASAN_NAND_CMD_CMD12_MASK;
794*4882a593Smuzhiyun 	reg_val |= curr_cmd->cmd1 |
795*4882a593Smuzhiyun 		   (curr_cmd->cmd2 << ARASAN_NAND_CMD_CMD2_SHIFT);
796*4882a593Smuzhiyun 	row_addr_cycles = arasan_nand_get_addrcycle(mtd);
797*4882a593Smuzhiyun 
798*4882a593Smuzhiyun 	if (row_addr_cycles == ARASAN_NAND_INVALID_ADDR_CYCL)
799*4882a593Smuzhiyun 		return ERR_ADDR_CYCLE;
800*4882a593Smuzhiyun 
801*4882a593Smuzhiyun 	reg_val &= ~ARASAN_NAND_CMD_ADDR_CYCL_MASK;
802*4882a593Smuzhiyun 	reg_val |= (row_addr_cycles <<
803*4882a593Smuzhiyun 		    ARASAN_NAND_CMD_ADDR_CYCL_SHIFT);
804*4882a593Smuzhiyun 
805*4882a593Smuzhiyun 	writel(reg_val, &arasan_nand_base->cmd_reg);
806*4882a593Smuzhiyun 
807*4882a593Smuzhiyun 	page = (page_addr >> ARASAN_NAND_MEM_ADDR1_PAGE_SHIFT) &
808*4882a593Smuzhiyun 		ARASAN_NAND_MEM_ADDR1_COL_MASK;
809*4882a593Smuzhiyun 	column = page_addr & ARASAN_NAND_MEM_ADDR1_COL_MASK;
810*4882a593Smuzhiyun 	writel(column | (page << ARASAN_NAND_MEM_ADDR1_PAGE_SHIFT),
811*4882a593Smuzhiyun 	       &arasan_nand_base->memadr_reg1);
812*4882a593Smuzhiyun 
813*4882a593Smuzhiyun 	reg_val = readl(&arasan_nand_base->memadr_reg2);
814*4882a593Smuzhiyun 	reg_val &= ~ARASAN_NAND_MEM_ADDR2_PAGE_MASK;
815*4882a593Smuzhiyun 	reg_val |= (page_addr >> ARASAN_NAND_MEM_ADDR1_PAGE_SHIFT);
816*4882a593Smuzhiyun 	writel(reg_val, &arasan_nand_base->memadr_reg2);
817*4882a593Smuzhiyun 	writel(curr_cmd->pgm, &arasan_nand_base->pgm_reg);
818*4882a593Smuzhiyun 
819*4882a593Smuzhiyun 	while (!(readl(&arasan_nand_base->intsts_reg) &
820*4882a593Smuzhiyun 		ARASAN_NAND_INT_STS_XFR_CMPLT_MASK) && timeout) {
821*4882a593Smuzhiyun 		udelay(1);
822*4882a593Smuzhiyun 		timeout--;
823*4882a593Smuzhiyun 	}
824*4882a593Smuzhiyun 	if (!timeout) {
825*4882a593Smuzhiyun 		printf("ERROR:%s timedout:Xfer CMPLT\n", __func__);
826*4882a593Smuzhiyun 		return -ETIMEDOUT;
827*4882a593Smuzhiyun 	}
828*4882a593Smuzhiyun 
829*4882a593Smuzhiyun 	reg_val = readl(&arasan_nand_base->intsts_enr);
830*4882a593Smuzhiyun 	writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
831*4882a593Smuzhiyun 	       &arasan_nand_base->intsts_enr);
832*4882a593Smuzhiyun 	reg_val = readl(&arasan_nand_base->intsts_reg);
833*4882a593Smuzhiyun 	writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
834*4882a593Smuzhiyun 	       &arasan_nand_base->intsts_reg);
835*4882a593Smuzhiyun 
836*4882a593Smuzhiyun 	return 0;
837*4882a593Smuzhiyun }
838*4882a593Smuzhiyun 
arasan_nand_read_status(struct arasan_nand_command_format * curr_cmd,int column,int page_addr,struct mtd_info * mtd)839*4882a593Smuzhiyun static int arasan_nand_read_status(struct arasan_nand_command_format *curr_cmd,
840*4882a593Smuzhiyun 				int column, int page_addr, struct mtd_info *mtd)
841*4882a593Smuzhiyun {
842*4882a593Smuzhiyun 	u32 reg_val;
843*4882a593Smuzhiyun 	u32 timeout = ARASAN_NAND_POLL_TIMEOUT;
844*4882a593Smuzhiyun 	u8 addr_cycles;
845*4882a593Smuzhiyun 
846*4882a593Smuzhiyun 	writel(ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
847*4882a593Smuzhiyun 	       &arasan_nand_base->intsts_enr);
848*4882a593Smuzhiyun 	reg_val = readl(&arasan_nand_base->cmd_reg);
849*4882a593Smuzhiyun 	reg_val &= ~ARASAN_NAND_CMD_CMD12_MASK;
850*4882a593Smuzhiyun 	reg_val |= curr_cmd->cmd1 |
851*4882a593Smuzhiyun 		   (curr_cmd->cmd2 << ARASAN_NAND_CMD_CMD2_SHIFT);
852*4882a593Smuzhiyun 	addr_cycles = arasan_nand_get_addrcycle(mtd);
853*4882a593Smuzhiyun 
854*4882a593Smuzhiyun 	if (addr_cycles == ARASAN_NAND_INVALID_ADDR_CYCL)
855*4882a593Smuzhiyun 		return ERR_ADDR_CYCLE;
856*4882a593Smuzhiyun 
857*4882a593Smuzhiyun 	reg_val &= ~ARASAN_NAND_CMD_ADDR_CYCL_MASK;
858*4882a593Smuzhiyun 	reg_val |= (addr_cycles <<
859*4882a593Smuzhiyun 		    ARASAN_NAND_CMD_ADDR_CYCL_SHIFT);
860*4882a593Smuzhiyun 
861*4882a593Smuzhiyun 	writel(reg_val, &arasan_nand_base->cmd_reg);
862*4882a593Smuzhiyun 
863*4882a593Smuzhiyun 	reg_val = readl(&arasan_nand_base->pkt_reg);
864*4882a593Smuzhiyun 	reg_val &= ~(ARASAN_NAND_PKT_REG_PKT_CNT_MASK |
865*4882a593Smuzhiyun 		     ARASAN_NAND_PKT_REG_PKT_SIZE_MASK);
866*4882a593Smuzhiyun 	reg_val |= (1 << ARASAN_NAND_PKT_REG_PKT_CNT_SHFT) | 1;
867*4882a593Smuzhiyun 	writel(reg_val, &arasan_nand_base->pkt_reg);
868*4882a593Smuzhiyun 
869*4882a593Smuzhiyun 	writel(curr_cmd->pgm, &arasan_nand_base->pgm_reg);
870*4882a593Smuzhiyun 	while (!(readl(&arasan_nand_base->intsts_reg) &
871*4882a593Smuzhiyun 		ARASAN_NAND_INT_STS_XFR_CMPLT_MASK) && timeout) {
872*4882a593Smuzhiyun 		udelay(1);
873*4882a593Smuzhiyun 		timeout--;
874*4882a593Smuzhiyun 	}
875*4882a593Smuzhiyun 
876*4882a593Smuzhiyun 	if (!timeout) {
877*4882a593Smuzhiyun 		printf("ERROR:%s: timedout:Xfer CMPLT\n", __func__);
878*4882a593Smuzhiyun 		return -ETIMEDOUT;
879*4882a593Smuzhiyun 	}
880*4882a593Smuzhiyun 
881*4882a593Smuzhiyun 	reg_val = readl(&arasan_nand_base->intsts_enr);
882*4882a593Smuzhiyun 	writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
883*4882a593Smuzhiyun 	       &arasan_nand_base->intsts_enr);
884*4882a593Smuzhiyun 	reg_val = readl(&arasan_nand_base->intsts_reg);
885*4882a593Smuzhiyun 	writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
886*4882a593Smuzhiyun 	       &arasan_nand_base->intsts_reg);
887*4882a593Smuzhiyun 
888*4882a593Smuzhiyun 	return 0;
889*4882a593Smuzhiyun }
890*4882a593Smuzhiyun 
arasan_nand_send_rdcmd(struct arasan_nand_command_format * curr_cmd,int column,int page_addr,struct mtd_info * mtd)891*4882a593Smuzhiyun static int arasan_nand_send_rdcmd(struct arasan_nand_command_format *curr_cmd,
892*4882a593Smuzhiyun 			       int column, int page_addr, struct mtd_info *mtd)
893*4882a593Smuzhiyun {
894*4882a593Smuzhiyun 	u32 reg_val, addr_cycles, page;
895*4882a593Smuzhiyun 	u8 page_val;
896*4882a593Smuzhiyun 
897*4882a593Smuzhiyun 	reg_val = readl(&arasan_nand_base->intsts_enr);
898*4882a593Smuzhiyun 	writel(reg_val | ARASAN_NAND_INT_STS_BUF_RD_RDY_MASK,
899*4882a593Smuzhiyun 	       &arasan_nand_base->intsts_enr);
900*4882a593Smuzhiyun 
901*4882a593Smuzhiyun 	reg_val = readl(&arasan_nand_base->cmd_reg);
902*4882a593Smuzhiyun 	reg_val &= ~ARASAN_NAND_CMD_CMD12_MASK;
903*4882a593Smuzhiyun 	reg_val |= curr_cmd->cmd1 |
904*4882a593Smuzhiyun 		   (curr_cmd->cmd2 << ARASAN_NAND_CMD_CMD2_SHIFT);
905*4882a593Smuzhiyun 
906*4882a593Smuzhiyun 	if (curr_cmd->cmd1 == NAND_CMD_RNDOUT ||
907*4882a593Smuzhiyun 	    curr_cmd->cmd1 == NAND_CMD_READ0) {
908*4882a593Smuzhiyun 		reg_val &= ~ARASAN_NAND_CMD_PG_SIZE_MASK;
909*4882a593Smuzhiyun 		page_val = arasan_nand_page(mtd);
910*4882a593Smuzhiyun 		reg_val |= (page_val << ARASAN_NAND_CMD_PG_SIZE_SHIFT);
911*4882a593Smuzhiyun 	}
912*4882a593Smuzhiyun 
913*4882a593Smuzhiyun 	reg_val &= ~ARASAN_NAND_CMD_ECC_ON_MASK;
914*4882a593Smuzhiyun 
915*4882a593Smuzhiyun 	reg_val &= ~ARASAN_NAND_CMD_ADDR_CYCL_MASK;
916*4882a593Smuzhiyun 
917*4882a593Smuzhiyun 	addr_cycles = arasan_nand_get_addrcycle(mtd);
918*4882a593Smuzhiyun 
919*4882a593Smuzhiyun 	if (addr_cycles == ARASAN_NAND_INVALID_ADDR_CYCL)
920*4882a593Smuzhiyun 		return ERR_ADDR_CYCLE;
921*4882a593Smuzhiyun 
922*4882a593Smuzhiyun 	reg_val |= (addr_cycles << 28);
923*4882a593Smuzhiyun 	writel(reg_val, &arasan_nand_base->cmd_reg);
924*4882a593Smuzhiyun 
925*4882a593Smuzhiyun 	if (page_addr == -1)
926*4882a593Smuzhiyun 		page_addr = 0;
927*4882a593Smuzhiyun 
928*4882a593Smuzhiyun 	page = (page_addr << ARASAN_NAND_MEM_ADDR1_PAGE_SHIFT) &
929*4882a593Smuzhiyun 		ARASAN_NAND_MEM_ADDR1_PAGE_MASK;
930*4882a593Smuzhiyun 	column &= ARASAN_NAND_MEM_ADDR1_COL_MASK;
931*4882a593Smuzhiyun 	writel(page | column, &arasan_nand_base->memadr_reg1);
932*4882a593Smuzhiyun 
933*4882a593Smuzhiyun 	reg_val = readl(&arasan_nand_base->memadr_reg2);
934*4882a593Smuzhiyun 	reg_val &= ~ARASAN_NAND_MEM_ADDR2_PAGE_MASK;
935*4882a593Smuzhiyun 	reg_val |= (page_addr >> ARASAN_NAND_MEM_ADDR1_PAGE_SHIFT);
936*4882a593Smuzhiyun 	writel(reg_val, &arasan_nand_base->memadr_reg2);
937*4882a593Smuzhiyun 
938*4882a593Smuzhiyun 	buf_index = 0;
939*4882a593Smuzhiyun 
940*4882a593Smuzhiyun 	return 0;
941*4882a593Smuzhiyun }
942*4882a593Smuzhiyun 
arasan_nand_read_buf(struct mtd_info * mtd,u8 * buf,int size)943*4882a593Smuzhiyun static void arasan_nand_read_buf(struct mtd_info *mtd, u8 *buf, int size)
944*4882a593Smuzhiyun {
945*4882a593Smuzhiyun 	u32 reg_val, i;
946*4882a593Smuzhiyun 	u32 *bufptr = (u32 *)buf;
947*4882a593Smuzhiyun 	u32 timeout = ARASAN_NAND_POLL_TIMEOUT;
948*4882a593Smuzhiyun 
949*4882a593Smuzhiyun 	reg_val = readl(&arasan_nand_base->pkt_reg);
950*4882a593Smuzhiyun 	reg_val &= ~(ARASAN_NAND_PKT_REG_PKT_CNT_MASK |
951*4882a593Smuzhiyun 		     ARASAN_NAND_PKT_REG_PKT_SIZE_MASK);
952*4882a593Smuzhiyun 	reg_val |= (1 << ARASAN_NAND_PKT_REG_PKT_CNT_SHFT) | size;
953*4882a593Smuzhiyun 	writel(reg_val, &arasan_nand_base->pkt_reg);
954*4882a593Smuzhiyun 
955*4882a593Smuzhiyun 	writel(curr_cmd->pgm, &arasan_nand_base->pgm_reg);
956*4882a593Smuzhiyun 
957*4882a593Smuzhiyun 	while (!(readl(&arasan_nand_base->intsts_reg) &
958*4882a593Smuzhiyun 		ARASAN_NAND_INT_STS_BUF_RD_RDY_MASK) && timeout) {
959*4882a593Smuzhiyun 		udelay(1);
960*4882a593Smuzhiyun 		timeout--;
961*4882a593Smuzhiyun 	}
962*4882a593Smuzhiyun 
963*4882a593Smuzhiyun 	if (!timeout)
964*4882a593Smuzhiyun 		puts("ERROR:arasan_nand_read_buf timedout:Buff RDY\n");
965*4882a593Smuzhiyun 
966*4882a593Smuzhiyun 	reg_val = readl(&arasan_nand_base->intsts_enr);
967*4882a593Smuzhiyun 	reg_val |= ARASAN_NAND_INT_STS_XFR_CMPLT_MASK;
968*4882a593Smuzhiyun 	writel(reg_val, &arasan_nand_base->intsts_enr);
969*4882a593Smuzhiyun 
970*4882a593Smuzhiyun 	writel(reg_val | ARASAN_NAND_INT_STS_BUF_RD_RDY_MASK,
971*4882a593Smuzhiyun 	       &arasan_nand_base->intsts_enr);
972*4882a593Smuzhiyun 	reg_val = readl(&arasan_nand_base->intsts_reg);
973*4882a593Smuzhiyun 	writel(reg_val | ARASAN_NAND_INT_STS_BUF_RD_RDY_MASK,
974*4882a593Smuzhiyun 	       &arasan_nand_base->intsts_reg);
975*4882a593Smuzhiyun 
976*4882a593Smuzhiyun 	buf_index = 0;
977*4882a593Smuzhiyun 	for (i = 0; i < size / 4; i++)
978*4882a593Smuzhiyun 		bufptr[i] = readl(&arasan_nand_base->buf_dataport);
979*4882a593Smuzhiyun 
980*4882a593Smuzhiyun 	if (size & 0x03)
981*4882a593Smuzhiyun 		bufptr[i] = readl(&arasan_nand_base->buf_dataport);
982*4882a593Smuzhiyun 
983*4882a593Smuzhiyun 	timeout = ARASAN_NAND_POLL_TIMEOUT;
984*4882a593Smuzhiyun 
985*4882a593Smuzhiyun 	while (!(readl(&arasan_nand_base->intsts_reg) &
986*4882a593Smuzhiyun 		ARASAN_NAND_INT_STS_XFR_CMPLT_MASK) && timeout) {
987*4882a593Smuzhiyun 		udelay(1);
988*4882a593Smuzhiyun 		timeout--;
989*4882a593Smuzhiyun 	}
990*4882a593Smuzhiyun 
991*4882a593Smuzhiyun 	if (!timeout)
992*4882a593Smuzhiyun 		puts("ERROR:arasan_nand_read_buf timedout:Xfer CMPLT\n");
993*4882a593Smuzhiyun 
994*4882a593Smuzhiyun 	reg_val = readl(&arasan_nand_base->intsts_enr);
995*4882a593Smuzhiyun 	writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
996*4882a593Smuzhiyun 	       &arasan_nand_base->intsts_enr);
997*4882a593Smuzhiyun 	reg_val = readl(&arasan_nand_base->intsts_reg);
998*4882a593Smuzhiyun 	writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
999*4882a593Smuzhiyun 	       &arasan_nand_base->intsts_reg);
1000*4882a593Smuzhiyun }
1001*4882a593Smuzhiyun 
arasan_nand_read_byte(struct mtd_info * mtd)1002*4882a593Smuzhiyun static u8 arasan_nand_read_byte(struct mtd_info *mtd)
1003*4882a593Smuzhiyun {
1004*4882a593Smuzhiyun 	struct nand_chip *chip = mtd_to_nand(mtd);
1005*4882a593Smuzhiyun 	u32 size;
1006*4882a593Smuzhiyun 	u8 val;
1007*4882a593Smuzhiyun 	struct nand_onfi_params *p;
1008*4882a593Smuzhiyun 
1009*4882a593Smuzhiyun 	if (buf_index == 0) {
1010*4882a593Smuzhiyun 		p = &chip->onfi_params;
1011*4882a593Smuzhiyun 		if (curr_cmd->cmd1 == NAND_CMD_READID)
1012*4882a593Smuzhiyun 			size = 4;
1013*4882a593Smuzhiyun 		else if (curr_cmd->cmd1 == NAND_CMD_PARAM)
1014*4882a593Smuzhiyun 			size = sizeof(struct nand_onfi_params);
1015*4882a593Smuzhiyun 		else if (curr_cmd->cmd1 == NAND_CMD_RNDOUT)
1016*4882a593Smuzhiyun 			size = le16_to_cpu(p->ext_param_page_length) * 16;
1017*4882a593Smuzhiyun 		else if (curr_cmd->cmd1 == NAND_CMD_GET_FEATURES)
1018*4882a593Smuzhiyun 			size = 4;
1019*4882a593Smuzhiyun 		else if (curr_cmd->cmd1 == NAND_CMD_STATUS)
1020*4882a593Smuzhiyun 			return readb(&arasan_nand_base->flash_sts_reg);
1021*4882a593Smuzhiyun 		else
1022*4882a593Smuzhiyun 			size = 8;
1023*4882a593Smuzhiyun 		chip->read_buf(mtd, &buf_data[0], size);
1024*4882a593Smuzhiyun 	}
1025*4882a593Smuzhiyun 
1026*4882a593Smuzhiyun 	val = *(&buf_data[0] + buf_index);
1027*4882a593Smuzhiyun 	buf_index++;
1028*4882a593Smuzhiyun 
1029*4882a593Smuzhiyun 	return val;
1030*4882a593Smuzhiyun }
1031*4882a593Smuzhiyun 
arasan_nand_cmd_function(struct mtd_info * mtd,unsigned int command,int column,int page_addr)1032*4882a593Smuzhiyun static void arasan_nand_cmd_function(struct mtd_info *mtd, unsigned int command,
1033*4882a593Smuzhiyun 				     int column, int page_addr)
1034*4882a593Smuzhiyun {
1035*4882a593Smuzhiyun 	u32 i, ret = 0;
1036*4882a593Smuzhiyun 	struct nand_chip *chip = mtd_to_nand(mtd);
1037*4882a593Smuzhiyun 	struct arasan_nand_info *nand = nand_get_controller_data(chip);
1038*4882a593Smuzhiyun 
1039*4882a593Smuzhiyun 	curr_cmd = NULL;
1040*4882a593Smuzhiyun 	writel(ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
1041*4882a593Smuzhiyun 	       &arasan_nand_base->intsts_enr);
1042*4882a593Smuzhiyun 
1043*4882a593Smuzhiyun 	if ((command == NAND_CMD_READOOB) &&
1044*4882a593Smuzhiyun 	    (mtd->writesize > 512)) {
1045*4882a593Smuzhiyun 		column += mtd->writesize;
1046*4882a593Smuzhiyun 		command = NAND_CMD_READ0;
1047*4882a593Smuzhiyun 	}
1048*4882a593Smuzhiyun 
1049*4882a593Smuzhiyun 	/* Get the command format */
1050*4882a593Smuzhiyun 	for (i = 0; (arasan_nand_commands[i].cmd1 != NAND_CMD_NONE ||
1051*4882a593Smuzhiyun 		     arasan_nand_commands[i].cmd2 != NAND_CMD_NONE); i++) {
1052*4882a593Smuzhiyun 		if (command == arasan_nand_commands[i].cmd1) {
1053*4882a593Smuzhiyun 			curr_cmd = &arasan_nand_commands[i];
1054*4882a593Smuzhiyun 			break;
1055*4882a593Smuzhiyun 		}
1056*4882a593Smuzhiyun 	}
1057*4882a593Smuzhiyun 
1058*4882a593Smuzhiyun 	if (curr_cmd == NULL) {
1059*4882a593Smuzhiyun 		printf("Unsupported Command; 0x%x\n", command);
1060*4882a593Smuzhiyun 		return;
1061*4882a593Smuzhiyun 	}
1062*4882a593Smuzhiyun 
1063*4882a593Smuzhiyun 	if (curr_cmd->cmd1 == NAND_CMD_RESET)
1064*4882a593Smuzhiyun 		ret = arasan_nand_reset(curr_cmd);
1065*4882a593Smuzhiyun 
1066*4882a593Smuzhiyun 	if ((curr_cmd->cmd1 == NAND_CMD_READID) ||
1067*4882a593Smuzhiyun 	    (curr_cmd->cmd1 == NAND_CMD_PARAM) ||
1068*4882a593Smuzhiyun 	    (curr_cmd->cmd1 == NAND_CMD_RNDOUT) ||
1069*4882a593Smuzhiyun 	    (curr_cmd->cmd1 == NAND_CMD_GET_FEATURES) ||
1070*4882a593Smuzhiyun 	    (curr_cmd->cmd1 == NAND_CMD_READ0))
1071*4882a593Smuzhiyun 		ret = arasan_nand_send_rdcmd(curr_cmd, column, page_addr, mtd);
1072*4882a593Smuzhiyun 
1073*4882a593Smuzhiyun 	if ((curr_cmd->cmd1 == NAND_CMD_SET_FEATURES) ||
1074*4882a593Smuzhiyun 	    (curr_cmd->cmd1 == NAND_CMD_SEQIN)) {
1075*4882a593Smuzhiyun 		nand->page = page_addr;
1076*4882a593Smuzhiyun 		ret = arasan_nand_send_wrcmd(curr_cmd, column, page_addr, mtd);
1077*4882a593Smuzhiyun 	}
1078*4882a593Smuzhiyun 
1079*4882a593Smuzhiyun 	if (curr_cmd->cmd1 == NAND_CMD_ERASE1)
1080*4882a593Smuzhiyun 		ret = arasan_nand_erase(curr_cmd, column, page_addr, mtd);
1081*4882a593Smuzhiyun 
1082*4882a593Smuzhiyun 	if (curr_cmd->cmd1 == NAND_CMD_STATUS)
1083*4882a593Smuzhiyun 		ret = arasan_nand_read_status(curr_cmd, column, page_addr, mtd);
1084*4882a593Smuzhiyun 
1085*4882a593Smuzhiyun 	if (ret != 0)
1086*4882a593Smuzhiyun 		printf("ERROR:%s:command:0x%x\n", __func__, curr_cmd->cmd1);
1087*4882a593Smuzhiyun }
1088*4882a593Smuzhiyun 
arasan_check_ondie(struct mtd_info * mtd)1089*4882a593Smuzhiyun static void arasan_check_ondie(struct mtd_info *mtd)
1090*4882a593Smuzhiyun {
1091*4882a593Smuzhiyun 	struct nand_chip *nand_chip = mtd_to_nand(mtd);
1092*4882a593Smuzhiyun 	struct arasan_nand_info *nand = nand_get_controller_data(nand_chip);
1093*4882a593Smuzhiyun 	u8 maf_id, dev_id;
1094*4882a593Smuzhiyun 	u8 get_feature[4];
1095*4882a593Smuzhiyun 	u8 set_feature[4] = {ENABLE_ONDIE_ECC, 0x00, 0x00, 0x00};
1096*4882a593Smuzhiyun 	u32 i;
1097*4882a593Smuzhiyun 
1098*4882a593Smuzhiyun 	/* Send the command for reading device ID */
1099*4882a593Smuzhiyun 	nand_chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
1100*4882a593Smuzhiyun 	nand_chip->cmdfunc(mtd, NAND_CMD_READID, 0, -1);
1101*4882a593Smuzhiyun 
1102*4882a593Smuzhiyun 	/* Read manufacturer and device IDs */
1103*4882a593Smuzhiyun 	maf_id = nand_chip->read_byte(mtd);
1104*4882a593Smuzhiyun 	dev_id = nand_chip->read_byte(mtd);
1105*4882a593Smuzhiyun 
1106*4882a593Smuzhiyun 	if ((maf_id == NAND_MFR_MICRON) &&
1107*4882a593Smuzhiyun 	    ((dev_id == 0xf1) || (dev_id == 0xa1) || (dev_id == 0xb1) ||
1108*4882a593Smuzhiyun 	     (dev_id == 0xaa) || (dev_id == 0xba) || (dev_id == 0xda) ||
1109*4882a593Smuzhiyun 	     (dev_id == 0xca) || (dev_id == 0xac) || (dev_id == 0xbc) ||
1110*4882a593Smuzhiyun 	     (dev_id == 0xdc) || (dev_id == 0xcc) || (dev_id == 0xa3) ||
1111*4882a593Smuzhiyun 	     (dev_id == 0xb3) || (dev_id == 0xd3) || (dev_id == 0xc3))) {
1112*4882a593Smuzhiyun 		nand_chip->cmdfunc(mtd, NAND_CMD_SET_FEATURES,
1113*4882a593Smuzhiyun 				   ONDIE_ECC_FEATURE_ADDR, -1);
1114*4882a593Smuzhiyun 
1115*4882a593Smuzhiyun 		nand_chip->write_buf(mtd, &set_feature[0], 4);
1116*4882a593Smuzhiyun 		nand_chip->cmdfunc(mtd, NAND_CMD_GET_FEATURES,
1117*4882a593Smuzhiyun 				   ONDIE_ECC_FEATURE_ADDR, -1);
1118*4882a593Smuzhiyun 
1119*4882a593Smuzhiyun 		for (i = 0; i < 4; i++)
1120*4882a593Smuzhiyun 			get_feature[i] = nand_chip->read_byte(mtd);
1121*4882a593Smuzhiyun 
1122*4882a593Smuzhiyun 		if (get_feature[0] & ENABLE_ONDIE_ECC)
1123*4882a593Smuzhiyun 			nand->on_die_ecc_enabled = true;
1124*4882a593Smuzhiyun 		else
1125*4882a593Smuzhiyun 			printf("%s: Unable to enable OnDie ECC\n", __func__);
1126*4882a593Smuzhiyun 
1127*4882a593Smuzhiyun 		/* Use the BBT pattern descriptors */
1128*4882a593Smuzhiyun 		nand_chip->bbt_td = &bbt_main_descr;
1129*4882a593Smuzhiyun 		nand_chip->bbt_md = &bbt_mirror_descr;
1130*4882a593Smuzhiyun 	}
1131*4882a593Smuzhiyun }
1132*4882a593Smuzhiyun 
arasan_nand_ecc_init(struct mtd_info * mtd)1133*4882a593Smuzhiyun static int arasan_nand_ecc_init(struct mtd_info *mtd)
1134*4882a593Smuzhiyun {
1135*4882a593Smuzhiyun 	int found = -1;
1136*4882a593Smuzhiyun 	u32 regval, eccpos_start, i, eccaddr;
1137*4882a593Smuzhiyun 	struct nand_chip *nand_chip = mtd_to_nand(mtd);
1138*4882a593Smuzhiyun 
1139*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(ecc_matrix); i++) {
1140*4882a593Smuzhiyun 		if ((ecc_matrix[i].pagesize == mtd->writesize) &&
1141*4882a593Smuzhiyun 		    (ecc_matrix[i].ecc_codeword_size >=
1142*4882a593Smuzhiyun 		     nand_chip->ecc_step_ds)) {
1143*4882a593Smuzhiyun 			if (ecc_matrix[i].eccbits >=
1144*4882a593Smuzhiyun 			    nand_chip->ecc_strength_ds) {
1145*4882a593Smuzhiyun 				found = i;
1146*4882a593Smuzhiyun 				break;
1147*4882a593Smuzhiyun 			}
1148*4882a593Smuzhiyun 			found = i;
1149*4882a593Smuzhiyun 		}
1150*4882a593Smuzhiyun 	}
1151*4882a593Smuzhiyun 
1152*4882a593Smuzhiyun 	if (found < 0)
1153*4882a593Smuzhiyun 		return 1;
1154*4882a593Smuzhiyun 
1155*4882a593Smuzhiyun 	eccaddr = mtd->writesize + mtd->oobsize -
1156*4882a593Smuzhiyun 		  ecc_matrix[found].eccsize;
1157*4882a593Smuzhiyun 
1158*4882a593Smuzhiyun 	regval = eccaddr |
1159*4882a593Smuzhiyun 		 (ecc_matrix[found].eccsize << ARASAN_NAND_ECC_SIZE_SHIFT) |
1160*4882a593Smuzhiyun 		 (ecc_matrix[found].bch << ARASAN_NAND_ECC_BCH_SHIFT);
1161*4882a593Smuzhiyun 	writel(regval, &arasan_nand_base->ecc_reg);
1162*4882a593Smuzhiyun 
1163*4882a593Smuzhiyun 	if (ecc_matrix[found].bch) {
1164*4882a593Smuzhiyun 		regval = readl(&arasan_nand_base->memadr_reg2);
1165*4882a593Smuzhiyun 		regval &= ~ARASAN_NAND_MEM_ADDR2_BCH_MASK;
1166*4882a593Smuzhiyun 		regval |= (ecc_matrix[found].bchval <<
1167*4882a593Smuzhiyun 			   ARASAN_NAND_MEM_ADDR2_BCH_SHIFT);
1168*4882a593Smuzhiyun 		writel(regval, &arasan_nand_base->memadr_reg2);
1169*4882a593Smuzhiyun 	}
1170*4882a593Smuzhiyun 
1171*4882a593Smuzhiyun 	nand_oob.eccbytes = ecc_matrix[found].eccsize;
1172*4882a593Smuzhiyun 	eccpos_start = mtd->oobsize - nand_oob.eccbytes;
1173*4882a593Smuzhiyun 
1174*4882a593Smuzhiyun 	for (i = 0; i < nand_oob.eccbytes; i++)
1175*4882a593Smuzhiyun 		nand_oob.eccpos[i] = eccpos_start + i;
1176*4882a593Smuzhiyun 
1177*4882a593Smuzhiyun 	nand_oob.oobfree[0].offset = 2;
1178*4882a593Smuzhiyun 	nand_oob.oobfree[0].length = eccpos_start - 2;
1179*4882a593Smuzhiyun 
1180*4882a593Smuzhiyun 	nand_chip->ecc.size = ecc_matrix[found].ecc_codeword_size;
1181*4882a593Smuzhiyun 	nand_chip->ecc.strength = ecc_matrix[found].eccbits;
1182*4882a593Smuzhiyun 	nand_chip->ecc.bytes = ecc_matrix[found].eccsize;
1183*4882a593Smuzhiyun 	nand_chip->ecc.layout = &nand_oob;
1184*4882a593Smuzhiyun 
1185*4882a593Smuzhiyun 	return 0;
1186*4882a593Smuzhiyun }
1187*4882a593Smuzhiyun 
arasan_nand_init(struct nand_chip * nand_chip,int devnum)1188*4882a593Smuzhiyun static int arasan_nand_init(struct nand_chip *nand_chip, int devnum)
1189*4882a593Smuzhiyun {
1190*4882a593Smuzhiyun 	struct arasan_nand_info *nand;
1191*4882a593Smuzhiyun 	struct mtd_info *mtd;
1192*4882a593Smuzhiyun 	int err = -1;
1193*4882a593Smuzhiyun 
1194*4882a593Smuzhiyun 	nand = calloc(1, sizeof(struct arasan_nand_info));
1195*4882a593Smuzhiyun 	if (!nand) {
1196*4882a593Smuzhiyun 		printf("%s: failed to allocate\n", __func__);
1197*4882a593Smuzhiyun 		return err;
1198*4882a593Smuzhiyun 	}
1199*4882a593Smuzhiyun 
1200*4882a593Smuzhiyun 	nand->nand_base = arasan_nand_base;
1201*4882a593Smuzhiyun 	mtd = nand_to_mtd(nand_chip);
1202*4882a593Smuzhiyun 	nand_set_controller_data(nand_chip, nand);
1203*4882a593Smuzhiyun 
1204*4882a593Smuzhiyun #ifdef CONFIG_SYS_NAND_NO_SUBPAGE_WRITE
1205*4882a593Smuzhiyun 	nand_chip->options |= NAND_NO_SUBPAGE_WRITE;
1206*4882a593Smuzhiyun #endif
1207*4882a593Smuzhiyun 
1208*4882a593Smuzhiyun 	/* Set the driver entry points for MTD */
1209*4882a593Smuzhiyun 	nand_chip->cmdfunc = arasan_nand_cmd_function;
1210*4882a593Smuzhiyun 	nand_chip->select_chip = arasan_nand_select_chip;
1211*4882a593Smuzhiyun 	nand_chip->read_byte = arasan_nand_read_byte;
1212*4882a593Smuzhiyun 
1213*4882a593Smuzhiyun 	/* Buffer read/write routines */
1214*4882a593Smuzhiyun 	nand_chip->read_buf = arasan_nand_read_buf;
1215*4882a593Smuzhiyun 	nand_chip->write_buf = arasan_nand_write_buf;
1216*4882a593Smuzhiyun 	nand_chip->bbt_options = NAND_BBT_USE_FLASH;
1217*4882a593Smuzhiyun 
1218*4882a593Smuzhiyun 	writel(0x0, &arasan_nand_base->cmd_reg);
1219*4882a593Smuzhiyun 	writel(0x0, &arasan_nand_base->pgm_reg);
1220*4882a593Smuzhiyun 
1221*4882a593Smuzhiyun 	/* first scan to find the device and get the page size */
1222*4882a593Smuzhiyun 	if (nand_scan_ident(mtd, CONFIG_SYS_NAND_MAX_CHIPS, NULL)) {
1223*4882a593Smuzhiyun 		printf("%s: nand_scan_ident failed\n", __func__);
1224*4882a593Smuzhiyun 		goto fail;
1225*4882a593Smuzhiyun 	}
1226*4882a593Smuzhiyun 
1227*4882a593Smuzhiyun 	nand_chip->ecc.mode = NAND_ECC_HW;
1228*4882a593Smuzhiyun 	nand_chip->ecc.hwctl = NULL;
1229*4882a593Smuzhiyun 	nand_chip->ecc.read_page = arasan_nand_read_page_hwecc;
1230*4882a593Smuzhiyun 	nand_chip->ecc.write_page = arasan_nand_write_page_hwecc;
1231*4882a593Smuzhiyun 	nand_chip->ecc.read_oob = arasan_nand_read_oob;
1232*4882a593Smuzhiyun 	nand_chip->ecc.write_oob = arasan_nand_write_oob;
1233*4882a593Smuzhiyun 
1234*4882a593Smuzhiyun 	arasan_check_ondie(mtd);
1235*4882a593Smuzhiyun 
1236*4882a593Smuzhiyun 	/*
1237*4882a593Smuzhiyun 	 * If on die supported, then give priority to on-die ecc and use
1238*4882a593Smuzhiyun 	 * it instead of controller ecc.
1239*4882a593Smuzhiyun 	 */
1240*4882a593Smuzhiyun 	if (nand->on_die_ecc_enabled) {
1241*4882a593Smuzhiyun 		nand_chip->ecc.strength = 1;
1242*4882a593Smuzhiyun 		nand_chip->ecc.size = mtd->writesize;
1243*4882a593Smuzhiyun 		nand_chip->ecc.bytes = 0;
1244*4882a593Smuzhiyun 		nand_chip->ecc.layout = &ondie_nand_oob_64;
1245*4882a593Smuzhiyun 	} else {
1246*4882a593Smuzhiyun 		if (arasan_nand_ecc_init(mtd)) {
1247*4882a593Smuzhiyun 			printf("%s: nand_ecc_init failed\n", __func__);
1248*4882a593Smuzhiyun 			goto fail;
1249*4882a593Smuzhiyun 		}
1250*4882a593Smuzhiyun 	}
1251*4882a593Smuzhiyun 
1252*4882a593Smuzhiyun 	if (nand_scan_tail(mtd)) {
1253*4882a593Smuzhiyun 		printf("%s: nand_scan_tail failed\n", __func__);
1254*4882a593Smuzhiyun 		goto fail;
1255*4882a593Smuzhiyun 	}
1256*4882a593Smuzhiyun 
1257*4882a593Smuzhiyun 	if (nand_register(devnum, mtd)) {
1258*4882a593Smuzhiyun 		printf("Nand Register Fail\n");
1259*4882a593Smuzhiyun 		goto fail;
1260*4882a593Smuzhiyun 	}
1261*4882a593Smuzhiyun 
1262*4882a593Smuzhiyun 	return 0;
1263*4882a593Smuzhiyun fail:
1264*4882a593Smuzhiyun 	free(nand);
1265*4882a593Smuzhiyun 	return err;
1266*4882a593Smuzhiyun }
1267*4882a593Smuzhiyun 
board_nand_init(void)1268*4882a593Smuzhiyun void board_nand_init(void)
1269*4882a593Smuzhiyun {
1270*4882a593Smuzhiyun 	struct nand_chip *nand = &nand_chip[0];
1271*4882a593Smuzhiyun 
1272*4882a593Smuzhiyun 	if (arasan_nand_init(nand, 0))
1273*4882a593Smuzhiyun 		puts("NAND init failed\n");
1274*4882a593Smuzhiyun }
1275