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