blob: ffcd963b3dacaa303cf0924fc42a3c5bbd3fd79a [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05302/*
3 * Arasan NAND Flash Controller Driver
4 *
5 * Copyright (C) 2014 - 2015 Xilinx, Inc.
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05306 */
7
Tom Riniabb9a042024-05-18 20:20:43 -06008#include <common.h>
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05309#include <malloc.h>
10#include <asm/io.h>
Simon Glassdbd79542020-05-10 11:40:11 -060011#include <linux/delay.h>
Masahiro Yamada56a931c2016-09-21 11:28:55 +090012#include <linux/errno.h>
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +053013#include <linux/mtd/mtd.h>
Masahiro Yamada2b7a8732017-11-30 13:45:24 +090014#include <linux/mtd/rawnand.h>
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +053015#include <linux/mtd/partitions.h>
16#include <linux/mtd/nand_ecc.h>
17#include <asm/arch/hardware.h>
18#include <asm/arch/sys_proto.h>
Ashok Reddy Somac7b66332019-12-19 02:27:42 -070019#include <dm.h>
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +053020#include <nand.h>
Simon Glassbdd5f812023-09-14 18:21:46 -060021#include <linux/printk.h>
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +053022
Ashok Reddy Somac7b66332019-12-19 02:27:42 -070023struct nand_config {
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +053024 u32 page;
Siva Durga Prasad Paladugu45e512c2018-01-04 16:04:21 +053025 bool on_die_ecc_enabled;
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +053026};
27
Ashok Reddy Soma13e92302019-12-19 02:27:43 -070028struct nand_drv {
29 struct nand_regs *reg;
30 struct nand_config config;
31};
32
Ashok Reddy Somac7b66332019-12-19 02:27:42 -070033struct arasan_nand_info {
34 struct udevice *dev;
Ashok Reddy Soma13e92302019-12-19 02:27:43 -070035 struct nand_drv nand_ctrl;
Ashok Reddy Somac7b66332019-12-19 02:27:42 -070036 struct nand_chip nand_chip;
37};
38
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +053039struct nand_regs {
40 u32 pkt_reg;
41 u32 memadr_reg1;
42 u32 memadr_reg2;
43 u32 cmd_reg;
44 u32 pgm_reg;
45 u32 intsts_enr;
46 u32 intsig_enr;
47 u32 intsts_reg;
48 u32 rdy_busy;
49 u32 cms_sysadr_reg;
50 u32 flash_sts_reg;
51 u32 tmg_reg;
52 u32 buf_dataport;
53 u32 ecc_reg;
54 u32 ecc_errcnt_reg;
55 u32 ecc_sprcmd_reg;
56 u32 errcnt_1bitreg;
57 u32 errcnt_2bitreg;
58 u32 errcnt_3bitreg;
59 u32 errcnt_4bitreg;
60 u32 dma_sysadr0_reg;
61 u32 dma_bufbdry_reg;
62 u32 cpu_rls_reg;
63 u32 errcnt_5bitreg;
64 u32 errcnt_6bitreg;
65 u32 errcnt_7bitreg;
66 u32 errcnt_8bitreg;
67 u32 data_if_reg;
68};
69
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +053070struct arasan_nand_command_format {
71 u8 cmd1;
72 u8 cmd2;
73 u8 addr_cycles;
74 u32 pgm;
75};
76
77#define ONDIE_ECC_FEATURE_ADDR 0x90
Siva Durga Prasad Paladugu45e512c2018-01-04 16:04:21 +053078#define ENABLE_ONDIE_ECC 0x08
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +053079
80#define ARASAN_PROG_RD_MASK 0x00000001
81#define ARASAN_PROG_BLK_ERS_MASK 0x00000004
82#define ARASAN_PROG_RD_ID_MASK 0x00000040
83#define ARASAN_PROG_RD_STS_MASK 0x00000008
84#define ARASAN_PROG_PG_PROG_MASK 0x00000010
85#define ARASAN_PROG_RD_PARAM_PG_MASK 0x00000080
86#define ARASAN_PROG_RST_MASK 0x00000100
87#define ARASAN_PROG_GET_FTRS_MASK 0x00000200
88#define ARASAN_PROG_SET_FTRS_MASK 0x00000400
89#define ARASAN_PROG_CHNG_ROWADR_END_MASK 0x00400000
90
91#define ARASAN_NAND_CMD_ECC_ON_MASK 0x80000000
92#define ARASAN_NAND_CMD_CMD12_MASK 0xFFFF
93#define ARASAN_NAND_CMD_PG_SIZE_MASK 0x3800000
94#define ARASAN_NAND_CMD_PG_SIZE_SHIFT 23
95#define ARASAN_NAND_CMD_CMD2_SHIFT 8
96#define ARASAN_NAND_CMD_ADDR_CYCL_MASK 0x70000000
97#define ARASAN_NAND_CMD_ADDR_CYCL_SHIFT 28
98
Vipul Kumar9d9b99b2018-03-10 17:52:23 +053099#define ARASAN_NAND_MEM_ADDR1_PAGE_MASK 0xFFFF0000
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530100#define ARASAN_NAND_MEM_ADDR1_COL_MASK 0xFFFF
101#define ARASAN_NAND_MEM_ADDR1_PAGE_SHIFT 16
102#define ARASAN_NAND_MEM_ADDR2_PAGE_MASK 0xFF
103#define ARASAN_NAND_MEM_ADDR2_CS_MASK 0xC0000000
T Karthik Reddy7cd85222018-12-03 16:11:58 +0530104#define ARASAN_NAND_MEM_ADDR2_CS0_MASK (0x3 << 30)
105#define ARASAN_NAND_MEM_ADDR2_CS1_MASK (0x1 << 30)
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530106#define ARASAN_NAND_MEM_ADDR2_BCH_MASK 0xE000000
107#define ARASAN_NAND_MEM_ADDR2_BCH_SHIFT 25
108
109#define ARASAN_NAND_INT_STS_ERR_EN_MASK 0x10
110#define ARASAN_NAND_INT_STS_MUL_BIT_ERR_MASK 0x08
111#define ARASAN_NAND_INT_STS_BUF_RD_RDY_MASK 0x02
112#define ARASAN_NAND_INT_STS_BUF_WR_RDY_MASK 0x01
113#define ARASAN_NAND_INT_STS_XFR_CMPLT_MASK 0x04
114
115#define ARASAN_NAND_PKT_REG_PKT_CNT_MASK 0xFFF000
116#define ARASAN_NAND_PKT_REG_PKT_SIZE_MASK 0x7FF
117#define ARASAN_NAND_PKT_REG_PKT_CNT_SHFT 12
118
119#define ARASAN_NAND_ROW_ADDR_CYCL_MASK 0x0F
120#define ARASAN_NAND_COL_ADDR_CYCL_MASK 0xF0
121#define ARASAN_NAND_COL_ADDR_CYCL_SHIFT 4
122
123#define ARASAN_NAND_ECC_SIZE_SHIFT 16
124#define ARASAN_NAND_ECC_BCH_SHIFT 27
125
126#define ARASAN_NAND_PKTSIZE_1K 1024
127#define ARASAN_NAND_PKTSIZE_512 512
128
129#define ARASAN_NAND_POLL_TIMEOUT 1000000
130#define ARASAN_NAND_INVALID_ADDR_CYCL 0xFF
131
132#define ERR_ADDR_CYCLE -1
133#define READ_BUFF_SIZE 0x4000
134
135static struct arasan_nand_command_format *curr_cmd;
136
137enum addr_cycles {
138 NAND_ADDR_CYCL_NONE,
139 NAND_ADDR_CYCL_ONE,
140 NAND_ADDR_CYCL_ROW,
141 NAND_ADDR_CYCL_COL,
142 NAND_ADDR_CYCL_BOTH,
143};
144
145static struct arasan_nand_command_format arasan_nand_commands[] = {
146 {NAND_CMD_READ0, NAND_CMD_READSTART, NAND_ADDR_CYCL_BOTH,
147 ARASAN_PROG_RD_MASK},
148 {NAND_CMD_RNDOUT, NAND_CMD_RNDOUTSTART, NAND_ADDR_CYCL_COL,
149 ARASAN_PROG_RD_MASK},
150 {NAND_CMD_READID, NAND_CMD_NONE, NAND_ADDR_CYCL_ONE,
151 ARASAN_PROG_RD_ID_MASK},
152 {NAND_CMD_STATUS, NAND_CMD_NONE, NAND_ADDR_CYCL_NONE,
153 ARASAN_PROG_RD_STS_MASK},
154 {NAND_CMD_SEQIN, NAND_CMD_PAGEPROG, NAND_ADDR_CYCL_BOTH,
155 ARASAN_PROG_PG_PROG_MASK},
156 {NAND_CMD_RNDIN, NAND_CMD_NONE, NAND_ADDR_CYCL_COL,
157 ARASAN_PROG_CHNG_ROWADR_END_MASK},
158 {NAND_CMD_ERASE1, NAND_CMD_ERASE2, NAND_ADDR_CYCL_ROW,
159 ARASAN_PROG_BLK_ERS_MASK},
160 {NAND_CMD_RESET, NAND_CMD_NONE, NAND_ADDR_CYCL_NONE,
161 ARASAN_PROG_RST_MASK},
162 {NAND_CMD_PARAM, NAND_CMD_NONE, NAND_ADDR_CYCL_ONE,
163 ARASAN_PROG_RD_PARAM_PG_MASK},
164 {NAND_CMD_GET_FEATURES, NAND_CMD_NONE, NAND_ADDR_CYCL_ONE,
165 ARASAN_PROG_GET_FTRS_MASK},
166 {NAND_CMD_SET_FEATURES, NAND_CMD_NONE, NAND_ADDR_CYCL_ONE,
167 ARASAN_PROG_SET_FTRS_MASK},
168 {NAND_CMD_NONE, NAND_CMD_NONE, NAND_ADDR_CYCL_NONE, 0},
169};
170
171struct arasan_ecc_matrix {
172 u32 pagesize;
173 u32 ecc_codeword_size;
174 u8 eccbits;
175 u8 bch;
176 u8 bchval;
177 u16 eccaddr;
178 u16 eccsize;
179};
180
181static const struct arasan_ecc_matrix ecc_matrix[] = {
182 {512, 512, 1, 0, 0, 0x20D, 0x3},
183 {512, 512, 4, 1, 3, 0x209, 0x7},
184 {512, 512, 8, 1, 2, 0x203, 0xD},
185 /*
186 * 2K byte page
187 */
188 {2048, 512, 1, 0, 0, 0x834, 0xC},
189 {2048, 512, 4, 1, 3, 0x826, 0x1A},
190 {2048, 512, 8, 1, 2, 0x80c, 0x34},
191 {2048, 512, 12, 1, 1, 0x822, 0x4E},
192 {2048, 512, 16, 1, 0, 0x808, 0x68},
193 {2048, 1024, 24, 1, 4, 0x81c, 0x54},
194 /*
195 * 4K byte page
196 */
197 {4096, 512, 1, 0, 0, 0x1068, 0x18},
198 {4096, 512, 4, 1, 3, 0x104c, 0x34},
199 {4096, 512, 8, 1, 2, 0x1018, 0x68},
200 {4096, 512, 12, 1, 1, 0x1044, 0x9C},
201 {4096, 512, 16, 1, 0, 0x1010, 0xD0},
202 {4096, 1024, 24, 1, 4, 0x1038, 0xA8},
203 /*
204 * 8K byte page
205 */
206 {8192, 512, 1, 0, 0, 0x20d0, 0x30},
207 {8192, 512, 4, 1, 3, 0x2098, 0x68},
208 {8192, 512, 8, 1, 2, 0x2030, 0xD0},
209 {8192, 512, 12, 1, 1, 0x2088, 0x138},
210 {8192, 512, 16, 1, 0, 0x2020, 0x1A0},
211 {8192, 1024, 24, 1, 4, 0x2070, 0x150},
212 /*
213 * 16K byte page
214 */
215 {16384, 512, 1, 0, 0, 0x4460, 0x60},
216 {16384, 512, 4, 1, 3, 0x43f0, 0xD0},
217 {16384, 512, 8, 1, 2, 0x4320, 0x1A0},
218 {16384, 512, 12, 1, 1, 0x4250, 0x270},
219 {16384, 512, 16, 1, 0, 0x4180, 0x340},
220 {16384, 1024, 24, 1, 4, 0x4220, 0x2A0}
221};
222
Siva Durga Prasad Paladugu45e512c2018-01-04 16:04:21 +0530223static struct nand_ecclayout ondie_nand_oob_64 = {
224 .eccbytes = 32,
225
226 .eccpos = {
227 8, 9, 10, 11, 12, 13, 14, 15,
228 24, 25, 26, 27, 28, 29, 30, 31,
229 40, 41, 42, 43, 44, 45, 46, 47,
230 56, 57, 58, 59, 60, 61, 62, 63
231 },
232
233 .oobfree = {
234 { .offset = 4, .length = 4 },
235 { .offset = 20, .length = 4 },
236 { .offset = 36, .length = 4 },
237 { .offset = 52, .length = 4 }
238 }
239};
240
241/*
242 * bbt decriptors for chips with on-die ECC and
243 * chips with 64-byte OOB
244 */
245static u8 bbt_pattern[] = {'B', 'b', 't', '0' };
246static u8 mirror_pattern[] = {'1', 't', 'b', 'B' };
247
248static struct nand_bbt_descr bbt_main_descr = {
249 .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE |
250 NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
251 .offs = 4,
252 .len = 4,
253 .veroffs = 20,
254 .maxblocks = 4,
255 .pattern = bbt_pattern
256};
257
258static struct nand_bbt_descr bbt_mirror_descr = {
259 .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE |
260 NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
261 .offs = 4,
262 .len = 4,
263 .veroffs = 20,
264 .maxblocks = 4,
265 .pattern = mirror_pattern
266};
267
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530268static u8 buf_data[READ_BUFF_SIZE];
269static u32 buf_index;
270
271static struct nand_ecclayout nand_oob;
272
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530273static void arasan_nand_select_chip(struct mtd_info *mtd, int chip)
274{
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700275 struct nand_chip *nand_chip = mtd_to_nand(mtd);
276 struct nand_drv *info = nand_get_controller_data(nand_chip);
T Karthik Reddy7cd85222018-12-03 16:11:58 +0530277 u32 reg_val;
278
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700279 reg_val = readl(&info->reg->memadr_reg2);
T Karthik Reddy7cd85222018-12-03 16:11:58 +0530280 if (chip == 0) {
281 reg_val &= ~ARASAN_NAND_MEM_ADDR2_CS0_MASK;
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700282 writel(reg_val, &info->reg->memadr_reg2);
T Karthik Reddy7cd85222018-12-03 16:11:58 +0530283 } else if (chip == 1) {
284 reg_val |= ARASAN_NAND_MEM_ADDR2_CS1_MASK;
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700285 writel(reg_val, &info->reg->memadr_reg2);
T Karthik Reddy7cd85222018-12-03 16:11:58 +0530286 }
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530287}
288
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700289static void arasan_nand_enable_ecc(struct mtd_info *mtd)
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530290{
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700291 struct nand_chip *chip = mtd_to_nand(mtd);
292 struct nand_drv *info = nand_get_controller_data(chip);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530293 u32 reg_val;
294
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700295 reg_val = readl(&info->reg->cmd_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530296 reg_val |= ARASAN_NAND_CMD_ECC_ON_MASK;
297
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700298 writel(reg_val, &info->reg->cmd_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530299}
300
301static u8 arasan_nand_get_addrcycle(struct mtd_info *mtd)
302{
303 u8 addrcycles;
Scott Wood17fed142016-05-30 13:57:56 -0500304 struct nand_chip *chip = mtd_to_nand(mtd);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530305
306 switch (curr_cmd->addr_cycles) {
307 case NAND_ADDR_CYCL_NONE:
308 addrcycles = 0;
309 break;
310 case NAND_ADDR_CYCL_ONE:
311 addrcycles = 1;
312 break;
313 case NAND_ADDR_CYCL_ROW:
314 addrcycles = chip->onfi_params.addr_cycles &
315 ARASAN_NAND_ROW_ADDR_CYCL_MASK;
316 break;
317 case NAND_ADDR_CYCL_COL:
318 addrcycles = (chip->onfi_params.addr_cycles &
319 ARASAN_NAND_COL_ADDR_CYCL_MASK) >>
320 ARASAN_NAND_COL_ADDR_CYCL_SHIFT;
321 break;
322 case NAND_ADDR_CYCL_BOTH:
323 addrcycles = chip->onfi_params.addr_cycles &
324 ARASAN_NAND_ROW_ADDR_CYCL_MASK;
325 addrcycles += (chip->onfi_params.addr_cycles &
326 ARASAN_NAND_COL_ADDR_CYCL_MASK) >>
327 ARASAN_NAND_COL_ADDR_CYCL_SHIFT;
328 break;
329 default:
330 addrcycles = ARASAN_NAND_INVALID_ADDR_CYCL;
331 break;
332 }
333 return addrcycles;
334}
335
336static int arasan_nand_read_page(struct mtd_info *mtd, u8 *buf, u32 size)
337{
Scott Wood17fed142016-05-30 13:57:56 -0500338 struct nand_chip *chip = mtd_to_nand(mtd);
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700339 struct nand_drv *info = nand_get_controller_data(chip);
340 struct nand_config *nand = &info->config;
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530341 u32 reg_val, i, pktsize, pktnum;
342 u32 *bufptr = (u32 *)buf;
343 u32 timeout;
344 u32 rdcount = 0;
345 u8 addr_cycles;
346
347 if (chip->ecc_step_ds >= ARASAN_NAND_PKTSIZE_1K)
348 pktsize = ARASAN_NAND_PKTSIZE_1K;
349 else
350 pktsize = ARASAN_NAND_PKTSIZE_512;
351
352 if (size % pktsize)
353 pktnum = size/pktsize + 1;
354 else
355 pktnum = size/pktsize;
356
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700357 reg_val = readl(&info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530358 reg_val |= ARASAN_NAND_INT_STS_ERR_EN_MASK |
359 ARASAN_NAND_INT_STS_MUL_BIT_ERR_MASK;
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700360 writel(reg_val, &info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530361
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700362 reg_val = readl(&info->reg->pkt_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530363 reg_val &= ~(ARASAN_NAND_PKT_REG_PKT_CNT_MASK |
364 ARASAN_NAND_PKT_REG_PKT_SIZE_MASK);
365 reg_val |= (pktnum << ARASAN_NAND_PKT_REG_PKT_CNT_SHFT) |
366 pktsize;
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700367 writel(reg_val, &info->reg->pkt_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530368
Siva Durga Prasad Paladugu45e512c2018-01-04 16:04:21 +0530369 if (!nand->on_die_ecc_enabled) {
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700370 arasan_nand_enable_ecc(mtd);
Siva Durga Prasad Paladugu45e512c2018-01-04 16:04:21 +0530371 addr_cycles = arasan_nand_get_addrcycle(mtd);
372 if (addr_cycles == ARASAN_NAND_INVALID_ADDR_CYCL)
373 return ERR_ADDR_CYCLE;
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530374
Siva Durga Prasad Paladugu45e512c2018-01-04 16:04:21 +0530375 writel((NAND_CMD_RNDOUTSTART << ARASAN_NAND_CMD_CMD2_SHIFT) |
376 NAND_CMD_RNDOUT | (addr_cycles <<
377 ARASAN_NAND_CMD_ADDR_CYCL_SHIFT),
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700378 &info->reg->ecc_sprcmd_reg);
Siva Durga Prasad Paladugu45e512c2018-01-04 16:04:21 +0530379 }
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700380 writel(curr_cmd->pgm, &info->reg->pgm_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530381
382 while (rdcount < pktnum) {
383 timeout = ARASAN_NAND_POLL_TIMEOUT;
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700384 while (!(readl(&info->reg->intsts_reg) &
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530385 ARASAN_NAND_INT_STS_BUF_RD_RDY_MASK) && timeout) {
386 udelay(1);
387 timeout--;
388 }
389 if (!timeout) {
390 puts("arasan_read_page: timedout:Buff RDY\n");
391 return -ETIMEDOUT;
392 }
393
394 rdcount++;
395
396 if (pktnum == rdcount) {
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700397 reg_val = readl(&info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530398 reg_val |= ARASAN_NAND_INT_STS_XFR_CMPLT_MASK;
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700399 writel(reg_val, &info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530400 } else {
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700401 reg_val = readl(&info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530402 writel(reg_val | ARASAN_NAND_INT_STS_BUF_RD_RDY_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700403 &info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530404 }
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700405 reg_val = readl(&info->reg->intsts_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530406 writel(reg_val | ARASAN_NAND_INT_STS_BUF_RD_RDY_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700407 &info->reg->intsts_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530408
409 for (i = 0; i < pktsize/4; i++)
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700410 bufptr[i] = readl(&info->reg->buf_dataport);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530411
412
413 bufptr += pktsize/4;
414
415 if (rdcount >= pktnum)
416 break;
417
418 writel(ARASAN_NAND_INT_STS_BUF_RD_RDY_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700419 &info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530420 }
421
422 timeout = ARASAN_NAND_POLL_TIMEOUT;
423
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700424 while (!(readl(&info->reg->intsts_reg) &
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530425 ARASAN_NAND_INT_STS_XFR_CMPLT_MASK) && timeout) {
426 udelay(1);
427 timeout--;
428 }
429 if (!timeout) {
430 puts("arasan rd_page timedout:Xfer CMPLT\n");
431 return -ETIMEDOUT;
432 }
433
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700434 reg_val = readl(&info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530435 writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700436 &info->reg->intsts_enr);
437 reg_val = readl(&info->reg->intsts_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530438 writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700439 &info->reg->intsts_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530440
Siva Durga Prasad Paladugu45e512c2018-01-04 16:04:21 +0530441 if (!nand->on_die_ecc_enabled) {
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700442 if (readl(&info->reg->intsts_reg) &
Siva Durga Prasad Paladugu45e512c2018-01-04 16:04:21 +0530443 ARASAN_NAND_INT_STS_MUL_BIT_ERR_MASK) {
444 printf("arasan rd_page:sbiterror\n");
445 return -1;
446 }
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530447
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700448 if (readl(&info->reg->intsts_reg) &
Siva Durga Prasad Paladugu45e512c2018-01-04 16:04:21 +0530449 ARASAN_NAND_INT_STS_ERR_EN_MASK) {
450 mtd->ecc_stats.failed++;
451 printf("arasan rd_page:multibiterror\n");
452 return -1;
453 }
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530454 }
455
456 return 0;
457}
458
459static int arasan_nand_read_page_hwecc(struct mtd_info *mtd,
460 struct nand_chip *chip, u8 *buf, int oob_required, int page)
461{
462 int status;
463
464 status = arasan_nand_read_page(mtd, buf, (mtd->writesize));
465
466 if (oob_required)
467 chip->ecc.read_oob(mtd, chip, page);
468
469 return status;
470}
471
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700472static void arasan_nand_fill_tx(struct mtd_info *mtd, const u8 *buf, int len)
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530473{
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700474 struct nand_chip *chip = mtd_to_nand(mtd);
475 struct nand_drv *info = nand_get_controller_data(chip);
476 u32 __iomem *nand = &info->reg->buf_dataport;
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530477
478 if (((unsigned long)buf & 0x3) != 0) {
479 if (((unsigned long)buf & 0x1) != 0) {
480 if (len) {
481 writeb(*buf, nand);
482 buf += 1;
483 len--;
484 }
485 }
486
487 if (((unsigned long)buf & 0x3) != 0) {
488 if (len >= 2) {
489 writew(*(u16 *)buf, nand);
490 buf += 2;
491 len -= 2;
492 }
493 }
494 }
495
496 while (len >= 4) {
497 writel(*(u32 *)buf, nand);
498 buf += 4;
499 len -= 4;
500 }
501
502 if (len) {
503 if (len >= 2) {
504 writew(*(u16 *)buf, nand);
505 buf += 2;
506 len -= 2;
507 }
508
509 if (len)
510 writeb(*buf, nand);
511 }
512}
513
514static int arasan_nand_write_page_hwecc(struct mtd_info *mtd,
Scott Wood46e13102016-05-30 13:57:57 -0500515 struct nand_chip *chip, const u8 *buf, int oob_required,
516 int page)
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530517{
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700518 struct nand_drv *info = nand_get_controller_data(chip);
519 struct nand_config *nand = &info->config;
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530520 u32 reg_val, i, pktsize, pktnum;
521 const u32 *bufptr = (const u32 *)buf;
522 u32 timeout = ARASAN_NAND_POLL_TIMEOUT;
523 u32 size = mtd->writesize;
524 u32 rdcount = 0;
525 u8 column_addr_cycles;
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530526
527 if (chip->ecc_step_ds >= ARASAN_NAND_PKTSIZE_1K)
528 pktsize = ARASAN_NAND_PKTSIZE_1K;
529 else
530 pktsize = ARASAN_NAND_PKTSIZE_512;
531
532 if (size % pktsize)
533 pktnum = size/pktsize + 1;
534 else
535 pktnum = size/pktsize;
536
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700537 reg_val = readl(&info->reg->pkt_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530538 reg_val &= ~(ARASAN_NAND_PKT_REG_PKT_CNT_MASK |
539 ARASAN_NAND_PKT_REG_PKT_SIZE_MASK);
540 reg_val |= (pktnum << ARASAN_NAND_PKT_REG_PKT_CNT_SHFT) | pktsize;
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700541 writel(reg_val, &info->reg->pkt_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530542
Siva Durga Prasad Paladugu45e512c2018-01-04 16:04:21 +0530543 if (!nand->on_die_ecc_enabled) {
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700544 arasan_nand_enable_ecc(mtd);
Siva Durga Prasad Paladugu45e512c2018-01-04 16:04:21 +0530545 column_addr_cycles = (chip->onfi_params.addr_cycles &
546 ARASAN_NAND_COL_ADDR_CYCL_MASK) >>
547 ARASAN_NAND_COL_ADDR_CYCL_SHIFT;
548 writel((NAND_CMD_RNDIN | (column_addr_cycles << 28)),
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700549 &info->reg->ecc_sprcmd_reg);
Siva Durga Prasad Paladugu45e512c2018-01-04 16:04:21 +0530550 }
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700551 writel(curr_cmd->pgm, &info->reg->pgm_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530552
553 while (rdcount < pktnum) {
554 timeout = ARASAN_NAND_POLL_TIMEOUT;
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700555 while (!(readl(&info->reg->intsts_reg) &
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530556 ARASAN_NAND_INT_STS_BUF_WR_RDY_MASK) && timeout) {
557 udelay(1);
558 timeout--;
559 }
560
561 if (!timeout) {
562 puts("arasan_write_page: timedout:Buff RDY\n");
563 return -ETIMEDOUT;
564 }
565
566 rdcount++;
567
568 if (pktnum == rdcount) {
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700569 reg_val = readl(&info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530570 reg_val |= ARASAN_NAND_INT_STS_XFR_CMPLT_MASK;
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700571 writel(reg_val, &info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530572 } else {
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700573 reg_val = readl(&info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530574 writel(reg_val | ARASAN_NAND_INT_STS_BUF_WR_RDY_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700575 &info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530576 }
577
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700578 reg_val = readl(&info->reg->intsts_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530579 writel(reg_val | ARASAN_NAND_INT_STS_BUF_WR_RDY_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700580 &info->reg->intsts_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530581
582 for (i = 0; i < pktsize/4; i++)
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700583 writel(bufptr[i], &info->reg->buf_dataport);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530584
585 bufptr += pktsize/4;
586
587 if (rdcount >= pktnum)
588 break;
589
590 writel(ARASAN_NAND_INT_STS_BUF_WR_RDY_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700591 &info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530592 }
593
594 timeout = ARASAN_NAND_POLL_TIMEOUT;
595
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700596 while (!(readl(&info->reg->intsts_reg) &
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530597 ARASAN_NAND_INT_STS_XFR_CMPLT_MASK) && timeout) {
598 udelay(1);
599 timeout--;
600 }
601 if (!timeout) {
602 puts("arasan write_page timedout:Xfer CMPLT\n");
603 return -ETIMEDOUT;
604 }
605
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700606 reg_val = readl(&info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530607 writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700608 &info->reg->intsts_enr);
609 reg_val = readl(&info->reg->intsts_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530610 writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700611 &info->reg->intsts_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530612
613 if (oob_required)
614 chip->ecc.write_oob(mtd, chip, nand->page);
615
616 return 0;
617}
618
619static int arasan_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
620 int page)
621{
622 chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
623 chip->read_buf(mtd, chip->oob_poi, (mtd->oobsize));
624
625 return 0;
626}
627
628static int arasan_nand_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
629 int page)
630{
631 int status = 0;
632 const u8 *buf = chip->oob_poi;
633
634 chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page);
635 chip->write_buf(mtd, buf, mtd->oobsize);
636
637 return status;
638}
639
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700640static int arasan_nand_reset(struct mtd_info *mtd,
641 struct arasan_nand_command_format *curr_cmd)
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530642{
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700643 struct nand_chip *chip = mtd_to_nand(mtd);
644 struct nand_drv *info = nand_get_controller_data(chip);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530645 u32 timeout = ARASAN_NAND_POLL_TIMEOUT;
646 u32 cmd_reg = 0;
647
648 writel(ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700649 &info->reg->intsts_enr);
650 cmd_reg = readl(&info->reg->cmd_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530651 cmd_reg &= ~ARASAN_NAND_CMD_CMD12_MASK;
652
653 cmd_reg |= curr_cmd->cmd1 |
654 (curr_cmd->cmd2 << ARASAN_NAND_CMD_CMD2_SHIFT);
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700655 writel(cmd_reg, &info->reg->cmd_reg);
656 writel(curr_cmd->pgm, &info->reg->pgm_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530657
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700658 while (!(readl(&info->reg->intsts_reg) &
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530659 ARASAN_NAND_INT_STS_XFR_CMPLT_MASK) && timeout) {
660 udelay(1);
661 timeout--;
662 }
663 if (!timeout) {
664 printf("ERROR:%s timedout\n", __func__);
665 return -ETIMEDOUT;
666 }
667
668 writel(ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700669 &info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530670
671 writel(ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700672 &info->reg->intsts_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530673
674 return 0;
675}
676
677static u8 arasan_nand_page(struct mtd_info *mtd)
678{
679 u8 page_val = 0;
680
681 switch (mtd->writesize) {
682 case 512:
683 page_val = 0;
684 break;
685 case 2048:
686 page_val = 1;
687 break;
688 case 4096:
689 page_val = 2;
690 break;
691 case 8192:
692 page_val = 3;
693 break;
694 case 16384:
695 page_val = 4;
696 break;
697 case 1024:
698 page_val = 5;
699 break;
700 default:
701 printf("%s:Pagesize>16K\n", __func__);
702 break;
703 }
704
705 return page_val;
706}
707
708static int arasan_nand_send_wrcmd(struct arasan_nand_command_format *curr_cmd,
709 int column, int page_addr, struct mtd_info *mtd)
710{
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700711 struct nand_chip *chip = mtd_to_nand(mtd);
712 struct nand_drv *info = nand_get_controller_data(chip);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530713 u32 reg_val, page;
714 u8 page_val, addr_cycles;
715
716 writel(ARASAN_NAND_INT_STS_BUF_WR_RDY_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700717 &info->reg->intsts_enr);
718 reg_val = readl(&info->reg->cmd_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530719 reg_val &= ~ARASAN_NAND_CMD_CMD12_MASK;
720 reg_val |= curr_cmd->cmd1 |
721 (curr_cmd->cmd2 << ARASAN_NAND_CMD_CMD2_SHIFT);
722 if (curr_cmd->cmd1 == NAND_CMD_SEQIN) {
723 reg_val &= ~ARASAN_NAND_CMD_PG_SIZE_MASK;
724 page_val = arasan_nand_page(mtd);
725 reg_val |= (page_val << ARASAN_NAND_CMD_PG_SIZE_SHIFT);
726 }
727
728 reg_val &= ~ARASAN_NAND_CMD_ADDR_CYCL_MASK;
729 addr_cycles = arasan_nand_get_addrcycle(mtd);
730
731 if (addr_cycles == ARASAN_NAND_INVALID_ADDR_CYCL)
732 return ERR_ADDR_CYCLE;
733
734 reg_val |= (addr_cycles <<
735 ARASAN_NAND_CMD_ADDR_CYCL_SHIFT);
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700736 writel(reg_val, &info->reg->cmd_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530737
738 if (page_addr == -1)
739 page_addr = 0;
740
741 page = (page_addr << ARASAN_NAND_MEM_ADDR1_PAGE_SHIFT) &
742 ARASAN_NAND_MEM_ADDR1_PAGE_MASK;
743 column &= ARASAN_NAND_MEM_ADDR1_COL_MASK;
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700744 writel(page | column, &info->reg->memadr_reg1);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530745
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700746 reg_val = readl(&info->reg->memadr_reg2);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530747 reg_val &= ~ARASAN_NAND_MEM_ADDR2_PAGE_MASK;
748 reg_val |= (page_addr >> ARASAN_NAND_MEM_ADDR1_PAGE_SHIFT);
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700749 writel(reg_val, &info->reg->memadr_reg2);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530750
751 return 0;
752}
753
754static void arasan_nand_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
755{
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700756 struct nand_chip *chip = mtd_to_nand(mtd);
757 struct nand_drv *info = nand_get_controller_data(chip);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530758 u32 reg_val;
759 u32 timeout = ARASAN_NAND_POLL_TIMEOUT;
760
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700761 reg_val = readl(&info->reg->pkt_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530762 reg_val &= ~(ARASAN_NAND_PKT_REG_PKT_CNT_MASK |
763 ARASAN_NAND_PKT_REG_PKT_SIZE_MASK);
764
765 reg_val |= (1 << ARASAN_NAND_PKT_REG_PKT_CNT_SHFT) | len;
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700766 writel(reg_val, &info->reg->pkt_reg);
767 writel(curr_cmd->pgm, &info->reg->pgm_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530768
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700769 while (!(readl(&info->reg->intsts_reg) &
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530770 ARASAN_NAND_INT_STS_BUF_WR_RDY_MASK) && timeout) {
771 udelay(1);
772 timeout--;
773 }
774
775 if (!timeout)
776 puts("ERROR:arasan_nand_write_buf timedout:Buff RDY\n");
777
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700778 reg_val = readl(&info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530779 reg_val |= ARASAN_NAND_INT_STS_XFR_CMPLT_MASK;
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700780 writel(reg_val, &info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530781 writel(reg_val | ARASAN_NAND_INT_STS_BUF_WR_RDY_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700782 &info->reg->intsts_enr);
783 reg_val = readl(&info->reg->intsts_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530784 writel(reg_val | ARASAN_NAND_INT_STS_BUF_WR_RDY_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700785 &info->reg->intsts_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530786
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700787 arasan_nand_fill_tx(mtd, buf, len);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530788
789 timeout = ARASAN_NAND_POLL_TIMEOUT;
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700790 while (!(readl(&info->reg->intsts_reg) &
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530791 ARASAN_NAND_INT_STS_XFR_CMPLT_MASK) && timeout) {
792 udelay(1);
793 timeout--;
794 }
795 if (!timeout)
796 puts("ERROR:arasan_nand_write_buf timedout:Xfer CMPLT\n");
797
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700798 writel(readl(&info->reg->intsts_enr) |
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530799 ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700800 &info->reg->intsts_enr);
801 writel(readl(&info->reg->intsts_reg) |
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530802 ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700803 &info->reg->intsts_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530804}
805
806static int arasan_nand_erase(struct arasan_nand_command_format *curr_cmd,
807 int column, int page_addr, struct mtd_info *mtd)
808{
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700809 struct nand_chip *chip = mtd_to_nand(mtd);
810 struct nand_drv *info = nand_get_controller_data(chip);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530811 u32 reg_val, page;
812 u32 timeout = ARASAN_NAND_POLL_TIMEOUT;
813 u8 row_addr_cycles;
814
815 writel(ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700816 &info->reg->intsts_enr);
817 reg_val = readl(&info->reg->cmd_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530818 reg_val &= ~ARASAN_NAND_CMD_CMD12_MASK;
819 reg_val |= curr_cmd->cmd1 |
820 (curr_cmd->cmd2 << ARASAN_NAND_CMD_CMD2_SHIFT);
821 row_addr_cycles = arasan_nand_get_addrcycle(mtd);
822
823 if (row_addr_cycles == ARASAN_NAND_INVALID_ADDR_CYCL)
824 return ERR_ADDR_CYCLE;
825
826 reg_val &= ~ARASAN_NAND_CMD_ADDR_CYCL_MASK;
827 reg_val |= (row_addr_cycles <<
828 ARASAN_NAND_CMD_ADDR_CYCL_SHIFT);
829
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700830 writel(reg_val, &info->reg->cmd_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530831
Vipul Kumar673a5c22018-03-05 15:24:59 +0530832 page = (page_addr >> ARASAN_NAND_MEM_ADDR1_PAGE_SHIFT) &
Vipul Kumar9d9b99b2018-03-10 17:52:23 +0530833 ARASAN_NAND_MEM_ADDR1_COL_MASK;
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530834 column = page_addr & ARASAN_NAND_MEM_ADDR1_COL_MASK;
Vipul Kumar673a5c22018-03-05 15:24:59 +0530835 writel(column | (page << ARASAN_NAND_MEM_ADDR1_PAGE_SHIFT),
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700836 &info->reg->memadr_reg1);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530837
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700838 reg_val = readl(&info->reg->memadr_reg2);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530839 reg_val &= ~ARASAN_NAND_MEM_ADDR2_PAGE_MASK;
840 reg_val |= (page_addr >> ARASAN_NAND_MEM_ADDR1_PAGE_SHIFT);
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700841 writel(reg_val, &info->reg->memadr_reg2);
842 writel(curr_cmd->pgm, &info->reg->pgm_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530843
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700844 while (!(readl(&info->reg->intsts_reg) &
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530845 ARASAN_NAND_INT_STS_XFR_CMPLT_MASK) && timeout) {
846 udelay(1);
847 timeout--;
848 }
849 if (!timeout) {
850 printf("ERROR:%s timedout:Xfer CMPLT\n", __func__);
851 return -ETIMEDOUT;
852 }
853
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700854 reg_val = readl(&info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530855 writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700856 &info->reg->intsts_enr);
857 reg_val = readl(&info->reg->intsts_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530858 writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700859 &info->reg->intsts_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530860
861 return 0;
862}
863
864static int arasan_nand_read_status(struct arasan_nand_command_format *curr_cmd,
865 int column, int page_addr, struct mtd_info *mtd)
866{
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700867 struct nand_chip *chip = mtd_to_nand(mtd);
868 struct nand_drv *info = nand_get_controller_data(chip);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530869 u32 reg_val;
870 u32 timeout = ARASAN_NAND_POLL_TIMEOUT;
871 u8 addr_cycles;
872
873 writel(ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700874 &info->reg->intsts_enr);
875 reg_val = readl(&info->reg->cmd_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530876 reg_val &= ~ARASAN_NAND_CMD_CMD12_MASK;
877 reg_val |= curr_cmd->cmd1 |
878 (curr_cmd->cmd2 << ARASAN_NAND_CMD_CMD2_SHIFT);
879 addr_cycles = arasan_nand_get_addrcycle(mtd);
880
881 if (addr_cycles == ARASAN_NAND_INVALID_ADDR_CYCL)
882 return ERR_ADDR_CYCLE;
883
884 reg_val &= ~ARASAN_NAND_CMD_ADDR_CYCL_MASK;
885 reg_val |= (addr_cycles <<
886 ARASAN_NAND_CMD_ADDR_CYCL_SHIFT);
887
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700888 writel(reg_val, &info->reg->cmd_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530889
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700890 reg_val = readl(&info->reg->pkt_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530891 reg_val &= ~(ARASAN_NAND_PKT_REG_PKT_CNT_MASK |
892 ARASAN_NAND_PKT_REG_PKT_SIZE_MASK);
893 reg_val |= (1 << ARASAN_NAND_PKT_REG_PKT_CNT_SHFT) | 1;
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700894 writel(reg_val, &info->reg->pkt_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530895
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700896 writel(curr_cmd->pgm, &info->reg->pgm_reg);
897 while (!(readl(&info->reg->intsts_reg) &
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530898 ARASAN_NAND_INT_STS_XFR_CMPLT_MASK) && timeout) {
899 udelay(1);
900 timeout--;
901 }
902
903 if (!timeout) {
904 printf("ERROR:%s: timedout:Xfer CMPLT\n", __func__);
905 return -ETIMEDOUT;
906 }
907
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700908 reg_val = readl(&info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530909 writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700910 &info->reg->intsts_enr);
911 reg_val = readl(&info->reg->intsts_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530912 writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700913 &info->reg->intsts_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530914
915 return 0;
916}
917
918static int arasan_nand_send_rdcmd(struct arasan_nand_command_format *curr_cmd,
919 int column, int page_addr, struct mtd_info *mtd)
920{
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700921 struct nand_chip *chip = mtd_to_nand(mtd);
922 struct nand_drv *info = nand_get_controller_data(chip);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530923 u32 reg_val, addr_cycles, page;
924 u8 page_val;
925
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700926 reg_val = readl(&info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530927 writel(reg_val | ARASAN_NAND_INT_STS_BUF_RD_RDY_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700928 &info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530929
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700930 reg_val = readl(&info->reg->cmd_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530931 reg_val &= ~ARASAN_NAND_CMD_CMD12_MASK;
932 reg_val |= curr_cmd->cmd1 |
933 (curr_cmd->cmd2 << ARASAN_NAND_CMD_CMD2_SHIFT);
934
935 if (curr_cmd->cmd1 == NAND_CMD_RNDOUT ||
936 curr_cmd->cmd1 == NAND_CMD_READ0) {
937 reg_val &= ~ARASAN_NAND_CMD_PG_SIZE_MASK;
938 page_val = arasan_nand_page(mtd);
939 reg_val |= (page_val << ARASAN_NAND_CMD_PG_SIZE_SHIFT);
940 }
941
Siva Durga Prasad Paladugu99459c22016-08-25 16:00:04 +0530942 reg_val &= ~ARASAN_NAND_CMD_ECC_ON_MASK;
943
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530944 reg_val &= ~ARASAN_NAND_CMD_ADDR_CYCL_MASK;
945
946 addr_cycles = arasan_nand_get_addrcycle(mtd);
947
948 if (addr_cycles == ARASAN_NAND_INVALID_ADDR_CYCL)
949 return ERR_ADDR_CYCLE;
950
951 reg_val |= (addr_cycles << 28);
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700952 writel(reg_val, &info->reg->cmd_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530953
954 if (page_addr == -1)
955 page_addr = 0;
956
957 page = (page_addr << ARASAN_NAND_MEM_ADDR1_PAGE_SHIFT) &
958 ARASAN_NAND_MEM_ADDR1_PAGE_MASK;
959 column &= ARASAN_NAND_MEM_ADDR1_COL_MASK;
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700960 writel(page | column, &info->reg->memadr_reg1);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530961
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700962 reg_val = readl(&info->reg->memadr_reg2);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530963 reg_val &= ~ARASAN_NAND_MEM_ADDR2_PAGE_MASK;
964 reg_val |= (page_addr >> ARASAN_NAND_MEM_ADDR1_PAGE_SHIFT);
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700965 writel(reg_val, &info->reg->memadr_reg2);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530966
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530967 buf_index = 0;
968
969 return 0;
970}
971
972static void arasan_nand_read_buf(struct mtd_info *mtd, u8 *buf, int size)
973{
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700974 struct nand_chip *chip = mtd_to_nand(mtd);
975 struct nand_drv *info = nand_get_controller_data(chip);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530976 u32 reg_val, i;
977 u32 *bufptr = (u32 *)buf;
978 u32 timeout = ARASAN_NAND_POLL_TIMEOUT;
979
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700980 reg_val = readl(&info->reg->pkt_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530981 reg_val &= ~(ARASAN_NAND_PKT_REG_PKT_CNT_MASK |
982 ARASAN_NAND_PKT_REG_PKT_SIZE_MASK);
983 reg_val |= (1 << ARASAN_NAND_PKT_REG_PKT_CNT_SHFT) | size;
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700984 writel(reg_val, &info->reg->pkt_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530985
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700986 writel(curr_cmd->pgm, &info->reg->pgm_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530987
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700988 while (!(readl(&info->reg->intsts_reg) &
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530989 ARASAN_NAND_INT_STS_BUF_RD_RDY_MASK) && timeout) {
990 udelay(1);
991 timeout--;
992 }
993
994 if (!timeout)
995 puts("ERROR:arasan_nand_read_buf timedout:Buff RDY\n");
996
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700997 reg_val = readl(&info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530998 reg_val |= ARASAN_NAND_INT_STS_XFR_CMPLT_MASK;
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700999 writel(reg_val, &info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301000
1001 writel(reg_val | ARASAN_NAND_INT_STS_BUF_RD_RDY_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -07001002 &info->reg->intsts_enr);
1003 reg_val = readl(&info->reg->intsts_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301004 writel(reg_val | ARASAN_NAND_INT_STS_BUF_RD_RDY_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -07001005 &info->reg->intsts_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301006
1007 buf_index = 0;
1008 for (i = 0; i < size / 4; i++)
Ashok Reddy Soma13e92302019-12-19 02:27:43 -07001009 bufptr[i] = readl(&info->reg->buf_dataport);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301010
1011 if (size & 0x03)
Ashok Reddy Soma13e92302019-12-19 02:27:43 -07001012 bufptr[i] = readl(&info->reg->buf_dataport);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301013
1014 timeout = ARASAN_NAND_POLL_TIMEOUT;
1015
Ashok Reddy Soma13e92302019-12-19 02:27:43 -07001016 while (!(readl(&info->reg->intsts_reg) &
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301017 ARASAN_NAND_INT_STS_XFR_CMPLT_MASK) && timeout) {
1018 udelay(1);
1019 timeout--;
1020 }
1021
1022 if (!timeout)
1023 puts("ERROR:arasan_nand_read_buf timedout:Xfer CMPLT\n");
1024
Ashok Reddy Soma13e92302019-12-19 02:27:43 -07001025 reg_val = readl(&info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301026 writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -07001027 &info->reg->intsts_enr);
1028 reg_val = readl(&info->reg->intsts_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301029 writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -07001030 &info->reg->intsts_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301031}
1032
1033static u8 arasan_nand_read_byte(struct mtd_info *mtd)
1034{
Scott Wood17fed142016-05-30 13:57:56 -05001035 struct nand_chip *chip = mtd_to_nand(mtd);
Ashok Reddy Soma13e92302019-12-19 02:27:43 -07001036 struct nand_drv *info = nand_get_controller_data(chip);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301037 u32 size;
1038 u8 val;
1039 struct nand_onfi_params *p;
1040
1041 if (buf_index == 0) {
1042 p = &chip->onfi_params;
1043 if (curr_cmd->cmd1 == NAND_CMD_READID)
1044 size = 4;
1045 else if (curr_cmd->cmd1 == NAND_CMD_PARAM)
1046 size = sizeof(struct nand_onfi_params);
1047 else if (curr_cmd->cmd1 == NAND_CMD_RNDOUT)
1048 size = le16_to_cpu(p->ext_param_page_length) * 16;
1049 else if (curr_cmd->cmd1 == NAND_CMD_GET_FEATURES)
1050 size = 4;
1051 else if (curr_cmd->cmd1 == NAND_CMD_STATUS)
Ashok Reddy Soma13e92302019-12-19 02:27:43 -07001052 return readb(&info->reg->flash_sts_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301053 else
1054 size = 8;
1055 chip->read_buf(mtd, &buf_data[0], size);
1056 }
1057
1058 val = *(&buf_data[0] + buf_index);
1059 buf_index++;
1060
1061 return val;
1062}
1063
1064static void arasan_nand_cmd_function(struct mtd_info *mtd, unsigned int command,
1065 int column, int page_addr)
1066{
Scott Wood17fed142016-05-30 13:57:56 -05001067 struct nand_chip *chip = mtd_to_nand(mtd);
Ashok Reddy Soma13e92302019-12-19 02:27:43 -07001068 struct nand_drv *info = nand_get_controller_data(chip);
1069 struct nand_config *nand = &info->config;
1070 u32 i, ret = 0;
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301071
1072 curr_cmd = NULL;
1073 writel(ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -07001074 &info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301075
1076 if ((command == NAND_CMD_READOOB) &&
1077 (mtd->writesize > 512)) {
1078 column += mtd->writesize;
1079 command = NAND_CMD_READ0;
1080 }
1081
1082 /* Get the command format */
1083 for (i = 0; (arasan_nand_commands[i].cmd1 != NAND_CMD_NONE ||
1084 arasan_nand_commands[i].cmd2 != NAND_CMD_NONE); i++) {
1085 if (command == arasan_nand_commands[i].cmd1) {
1086 curr_cmd = &arasan_nand_commands[i];
1087 break;
1088 }
1089 }
1090
1091 if (curr_cmd == NULL) {
1092 printf("Unsupported Command; 0x%x\n", command);
1093 return;
1094 }
1095
1096 if (curr_cmd->cmd1 == NAND_CMD_RESET)
Ashok Reddy Soma13e92302019-12-19 02:27:43 -07001097 ret = arasan_nand_reset(mtd, curr_cmd);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301098
1099 if ((curr_cmd->cmd1 == NAND_CMD_READID) ||
1100 (curr_cmd->cmd1 == NAND_CMD_PARAM) ||
1101 (curr_cmd->cmd1 == NAND_CMD_RNDOUT) ||
1102 (curr_cmd->cmd1 == NAND_CMD_GET_FEATURES) ||
1103 (curr_cmd->cmd1 == NAND_CMD_READ0))
1104 ret = arasan_nand_send_rdcmd(curr_cmd, column, page_addr, mtd);
1105
1106 if ((curr_cmd->cmd1 == NAND_CMD_SET_FEATURES) ||
1107 (curr_cmd->cmd1 == NAND_CMD_SEQIN)) {
1108 nand->page = page_addr;
1109 ret = arasan_nand_send_wrcmd(curr_cmd, column, page_addr, mtd);
1110 }
1111
1112 if (curr_cmd->cmd1 == NAND_CMD_ERASE1)
1113 ret = arasan_nand_erase(curr_cmd, column, page_addr, mtd);
1114
1115 if (curr_cmd->cmd1 == NAND_CMD_STATUS)
1116 ret = arasan_nand_read_status(curr_cmd, column, page_addr, mtd);
1117
1118 if (ret != 0)
1119 printf("ERROR:%s:command:0x%x\n", __func__, curr_cmd->cmd1);
1120}
1121
Siva Durga Prasad Paladugu45e512c2018-01-04 16:04:21 +05301122static void arasan_check_ondie(struct mtd_info *mtd)
1123{
1124 struct nand_chip *nand_chip = mtd_to_nand(mtd);
T Karthik Reddy4de4f382020-01-19 23:59:23 -07001125 struct nand_drv *info = nand_get_controller_data(nand_chip);
1126 struct nand_config *nand = &info->config;
Siva Durga Prasad Paladugu45e512c2018-01-04 16:04:21 +05301127 u8 maf_id, dev_id;
1128 u8 get_feature[4];
1129 u8 set_feature[4] = {ENABLE_ONDIE_ECC, 0x00, 0x00, 0x00};
1130 u32 i;
1131
T Karthik Reddy4de4f382020-01-19 23:59:23 -07001132 nand_chip->select_chip(mtd, 0);
1133
Siva Durga Prasad Paladugu45e512c2018-01-04 16:04:21 +05301134 /* Send the command for reading device ID */
1135 nand_chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
1136 nand_chip->cmdfunc(mtd, NAND_CMD_READID, 0, -1);
1137
1138 /* Read manufacturer and device IDs */
1139 maf_id = nand_chip->read_byte(mtd);
1140 dev_id = nand_chip->read_byte(mtd);
1141
1142 if ((maf_id == NAND_MFR_MICRON) &&
1143 ((dev_id == 0xf1) || (dev_id == 0xa1) || (dev_id == 0xb1) ||
1144 (dev_id == 0xaa) || (dev_id == 0xba) || (dev_id == 0xda) ||
1145 (dev_id == 0xca) || (dev_id == 0xac) || (dev_id == 0xbc) ||
1146 (dev_id == 0xdc) || (dev_id == 0xcc) || (dev_id == 0xa3) ||
1147 (dev_id == 0xb3) || (dev_id == 0xd3) || (dev_id == 0xc3))) {
1148 nand_chip->cmdfunc(mtd, NAND_CMD_SET_FEATURES,
1149 ONDIE_ECC_FEATURE_ADDR, -1);
1150
1151 nand_chip->write_buf(mtd, &set_feature[0], 4);
1152 nand_chip->cmdfunc(mtd, NAND_CMD_GET_FEATURES,
1153 ONDIE_ECC_FEATURE_ADDR, -1);
1154
1155 for (i = 0; i < 4; i++)
1156 get_feature[i] = nand_chip->read_byte(mtd);
1157
T Karthik Reddy4de4f382020-01-19 23:59:23 -07001158 if (get_feature[0] & ENABLE_ONDIE_ECC) {
Siva Durga Prasad Paladugu45e512c2018-01-04 16:04:21 +05301159 nand->on_die_ecc_enabled = true;
T Karthik Reddy4de4f382020-01-19 23:59:23 -07001160 printf("On-DIE ECC Enabled\n");
1161 } else {
Siva Durga Prasad Paladugu45e512c2018-01-04 16:04:21 +05301162 printf("%s: Unable to enable OnDie ECC\n", __func__);
T Karthik Reddy4de4f382020-01-19 23:59:23 -07001163 }
Siva Durga Prasad Paladugu45e512c2018-01-04 16:04:21 +05301164
1165 /* Use the BBT pattern descriptors */
1166 nand_chip->bbt_td = &bbt_main_descr;
1167 nand_chip->bbt_md = &bbt_mirror_descr;
1168 }
1169}
1170
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301171static int arasan_nand_ecc_init(struct mtd_info *mtd)
1172{
Ashok Reddy Soma13e92302019-12-19 02:27:43 -07001173 struct nand_chip *nand_chip = mtd_to_nand(mtd);
1174 struct nand_drv *info = nand_get_controller_data(nand_chip);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301175 int found = -1;
Siva Durga Prasad Paladugub0a4f132018-01-04 16:04:22 +05301176 u32 regval, eccpos_start, i, eccaddr;
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301177
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301178 for (i = 0; i < ARRAY_SIZE(ecc_matrix); i++) {
1179 if ((ecc_matrix[i].pagesize == mtd->writesize) &&
1180 (ecc_matrix[i].ecc_codeword_size >=
1181 nand_chip->ecc_step_ds)) {
1182 if (ecc_matrix[i].eccbits >=
1183 nand_chip->ecc_strength_ds) {
1184 found = i;
1185 break;
1186 }
1187 found = i;
1188 }
1189 }
1190
1191 if (found < 0)
1192 return 1;
1193
Siva Durga Prasad Paladugub0a4f132018-01-04 16:04:22 +05301194 eccaddr = mtd->writesize + mtd->oobsize -
1195 ecc_matrix[found].eccsize;
1196
1197 regval = eccaddr |
Siva Durga Prasad Paladugudb796632016-05-25 15:20:38 +05301198 (ecc_matrix[found].eccsize << ARASAN_NAND_ECC_SIZE_SHIFT) |
1199 (ecc_matrix[found].bch << ARASAN_NAND_ECC_BCH_SHIFT);
Ashok Reddy Soma13e92302019-12-19 02:27:43 -07001200 writel(regval, &info->reg->ecc_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301201
Siva Durga Prasad Paladugudb796632016-05-25 15:20:38 +05301202 if (ecc_matrix[found].bch) {
Ashok Reddy Soma13e92302019-12-19 02:27:43 -07001203 regval = readl(&info->reg->memadr_reg2);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301204 regval &= ~ARASAN_NAND_MEM_ADDR2_BCH_MASK;
Siva Durga Prasad Paladugudb796632016-05-25 15:20:38 +05301205 regval |= (ecc_matrix[found].bchval <<
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301206 ARASAN_NAND_MEM_ADDR2_BCH_SHIFT);
Ashok Reddy Soma13e92302019-12-19 02:27:43 -07001207 writel(regval, &info->reg->memadr_reg2);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301208 }
1209
Siva Durga Prasad Paladugudb796632016-05-25 15:20:38 +05301210 nand_oob.eccbytes = ecc_matrix[found].eccsize;
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301211 eccpos_start = mtd->oobsize - nand_oob.eccbytes;
1212
1213 for (i = 0; i < nand_oob.eccbytes; i++)
1214 nand_oob.eccpos[i] = eccpos_start + i;
1215
1216 nand_oob.oobfree[0].offset = 2;
1217 nand_oob.oobfree[0].length = eccpos_start - 2;
1218
Siva Durga Prasad Paladugudb796632016-05-25 15:20:38 +05301219 nand_chip->ecc.size = ecc_matrix[found].ecc_codeword_size;
1220 nand_chip->ecc.strength = ecc_matrix[found].eccbits;
1221 nand_chip->ecc.bytes = ecc_matrix[found].eccsize;
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301222 nand_chip->ecc.layout = &nand_oob;
1223
1224 return 0;
1225}
1226
Ashok Reddy Somac7b66332019-12-19 02:27:42 -07001227static int arasan_probe(struct udevice *dev)
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301228{
Ashok Reddy Somac7b66332019-12-19 02:27:42 -07001229 struct arasan_nand_info *arasan = dev_get_priv(dev);
1230 struct nand_chip *nand_chip = &arasan->nand_chip;
Ashok Reddy Soma13e92302019-12-19 02:27:43 -07001231 struct nand_drv *info = &arasan->nand_ctrl;
1232 struct nand_config *nand = &info->config;
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301233 struct mtd_info *mtd;
Ashok Reddy Somaaf1d3cf2023-02-23 22:07:07 -07001234 ofnode child;
Venkatesh Yadav Abbarapu7a1d17a2024-03-06 09:04:04 +05301235 int ret;
Venkatesh Yadav Abbarapu263fa962024-03-06 08:57:03 +05301236 const char *str;
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301237
Johan Jonker8d5d8e02023-03-13 01:32:04 +01001238 info->reg = dev_read_addr_ptr(dev);
Scott Wood17fed142016-05-30 13:57:56 -05001239 mtd = nand_to_mtd(nand_chip);
Ashok Reddy Soma13e92302019-12-19 02:27:43 -07001240 nand_set_controller_data(nand_chip, &arasan->nand_ctrl);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301241
Ashok Reddy Somaaf1d3cf2023-02-23 22:07:07 -07001242 ofnode_for_each_subnode(child, dev_ofnode(dev))
1243 nand_set_flash_node(nand_chip, child);
1244
Martin Lund5f9ae0e2018-10-30 14:16:19 +01001245#ifdef CONFIG_SYS_NAND_NO_SUBPAGE_WRITE
1246 nand_chip->options |= NAND_NO_SUBPAGE_WRITE;
1247#endif
1248
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301249 /* Set the driver entry points for MTD */
1250 nand_chip->cmdfunc = arasan_nand_cmd_function;
1251 nand_chip->select_chip = arasan_nand_select_chip;
1252 nand_chip->read_byte = arasan_nand_read_byte;
1253
1254 /* Buffer read/write routines */
1255 nand_chip->read_buf = arasan_nand_read_buf;
1256 nand_chip->write_buf = arasan_nand_write_buf;
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301257
Ashok Reddy Soma13e92302019-12-19 02:27:43 -07001258 writel(0x0, &info->reg->cmd_reg);
1259 writel(0x0, &info->reg->pgm_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301260
1261 /* first scan to find the device and get the page size */
Venkatesh Yadav Abbarapu7a1d17a2024-03-06 09:04:04 +05301262 ret = nand_scan_ident(mtd, CONFIG_SYS_NAND_MAX_CHIPS, NULL);
1263 if (ret) {
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301264 printf("%s: nand_scan_ident failed\n", __func__);
Venkatesh Yadav Abbarapu7a1d17a2024-03-06 09:04:04 +05301265 return ret;
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301266 }
1267
Venkatesh Yadav Abbarapu263fa962024-03-06 08:57:03 +05301268 str = ofnode_read_string(nand_chip->flash_node, "nand-ecc-mode");
1269 if (!str || strcmp(str, "hw") != 0) {
1270 printf("%s ecc mode is not supported\n", str);
1271 return -EINVAL;
1272 }
1273
Siva Durga Prasad Paladugu80c889c2018-01-04 16:04:20 +05301274 nand_chip->ecc.mode = NAND_ECC_HW;
1275 nand_chip->ecc.hwctl = NULL;
1276 nand_chip->ecc.read_page = arasan_nand_read_page_hwecc;
1277 nand_chip->ecc.write_page = arasan_nand_write_page_hwecc;
1278 nand_chip->ecc.read_oob = arasan_nand_read_oob;
1279 nand_chip->ecc.write_oob = arasan_nand_write_oob;
1280
Siva Durga Prasad Paladugu45e512c2018-01-04 16:04:21 +05301281 arasan_check_ondie(mtd);
1282
1283 /*
1284 * If on die supported, then give priority to on-die ecc and use
1285 * it instead of controller ecc.
1286 */
1287 if (nand->on_die_ecc_enabled) {
1288 nand_chip->ecc.strength = 1;
1289 nand_chip->ecc.size = mtd->writesize;
1290 nand_chip->ecc.bytes = 0;
1291 nand_chip->ecc.layout = &ondie_nand_oob_64;
1292 } else {
Venkatesh Yadav Abbarapu7a1d17a2024-03-06 09:04:04 +05301293 ret = arasan_nand_ecc_init(mtd);
1294 if (ret) {
Siva Durga Prasad Paladugu45e512c2018-01-04 16:04:21 +05301295 printf("%s: nand_ecc_init failed\n", __func__);
Venkatesh Yadav Abbarapu7a1d17a2024-03-06 09:04:04 +05301296 return ret;
Siva Durga Prasad Paladugu45e512c2018-01-04 16:04:21 +05301297 }
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301298 }
1299
Venkatesh Yadav Abbarapu7a1d17a2024-03-06 09:04:04 +05301300 ret = nand_scan_tail(mtd);
1301 if (ret) {
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301302 printf("%s: nand_scan_tail failed\n", __func__);
Venkatesh Yadav Abbarapu7a1d17a2024-03-06 09:04:04 +05301303 return ret;
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301304 }
1305
Venkatesh Yadav Abbarapu7a1d17a2024-03-06 09:04:04 +05301306 ret = nand_register(0, mtd);
1307 if (ret) {
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301308 printf("Nand Register Fail\n");
Venkatesh Yadav Abbarapu7a1d17a2024-03-06 09:04:04 +05301309 return ret;
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301310 }
1311
Venkatesh Yadav Abbarapu7a1d17a2024-03-06 09:04:04 +05301312 return ret;
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301313}
1314
Ashok Reddy Somac7b66332019-12-19 02:27:42 -07001315static const struct udevice_id arasan_nand_dt_ids[] = {
1316 {.compatible = "arasan,nfc-v3p10",},
1317 { /* sentinel */ }
1318};
1319
1320U_BOOT_DRIVER(arasan_nand) = {
Michal Simek33093082020-01-07 08:50:34 +01001321 .name = "arasan_nand",
Ashok Reddy Somac7b66332019-12-19 02:27:42 -07001322 .id = UCLASS_MTD,
1323 .of_match = arasan_nand_dt_ids,
1324 .probe = arasan_probe,
Simon Glass8a2b47f2020-12-03 16:55:17 -07001325 .priv_auto = sizeof(struct arasan_nand_info),
Ashok Reddy Somac7b66332019-12-19 02:27:42 -07001326};
1327
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301328void board_nand_init(void)
1329{
Ashok Reddy Somac7b66332019-12-19 02:27:42 -07001330 struct udevice *dev;
1331 int ret;
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301332
Ashok Reddy Somac7b66332019-12-19 02:27:42 -07001333 ret = uclass_get_device_by_driver(UCLASS_MTD,
Simon Glass65130cd2020-12-28 20:34:56 -07001334 DM_DRIVER_GET(arasan_nand), &dev);
Ashok Reddy Somac7b66332019-12-19 02:27:42 -07001335 if (ret && ret != -ENODEV)
1336 pr_err("Failed to initialize %s. (error %d)\n", dev->name, ret);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301337}