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