blob: 587941290dcc5a784b524fb6179b0751a2065703 [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
8#include <common.h>
9#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>
21
Ashok Reddy Somac7b66332019-12-19 02:27:42 -070022struct nand_config {
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +053023 u32 page;
Siva Durga Prasad Paladugu45e512c2018-01-04 16:04:21 +053024 bool on_die_ecc_enabled;
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +053025};
26
Ashok Reddy Soma13e92302019-12-19 02:27:43 -070027struct nand_drv {
28 struct nand_regs *reg;
29 struct nand_config config;
30};
31
Ashok Reddy Somac7b66332019-12-19 02:27:42 -070032struct arasan_nand_info {
33 struct udevice *dev;
Ashok Reddy Soma13e92302019-12-19 02:27:43 -070034 struct nand_drv nand_ctrl;
Ashok Reddy Somac7b66332019-12-19 02:27:42 -070035 struct nand_chip nand_chip;
36};
37
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +053038struct nand_regs {
39 u32 pkt_reg;
40 u32 memadr_reg1;
41 u32 memadr_reg2;
42 u32 cmd_reg;
43 u32 pgm_reg;
44 u32 intsts_enr;
45 u32 intsig_enr;
46 u32 intsts_reg;
47 u32 rdy_busy;
48 u32 cms_sysadr_reg;
49 u32 flash_sts_reg;
50 u32 tmg_reg;
51 u32 buf_dataport;
52 u32 ecc_reg;
53 u32 ecc_errcnt_reg;
54 u32 ecc_sprcmd_reg;
55 u32 errcnt_1bitreg;
56 u32 errcnt_2bitreg;
57 u32 errcnt_3bitreg;
58 u32 errcnt_4bitreg;
59 u32 dma_sysadr0_reg;
60 u32 dma_bufbdry_reg;
61 u32 cpu_rls_reg;
62 u32 errcnt_5bitreg;
63 u32 errcnt_6bitreg;
64 u32 errcnt_7bitreg;
65 u32 errcnt_8bitreg;
66 u32 data_if_reg;
67};
68
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +053069struct arasan_nand_command_format {
70 u8 cmd1;
71 u8 cmd2;
72 u8 addr_cycles;
73 u32 pgm;
74};
75
76#define ONDIE_ECC_FEATURE_ADDR 0x90
Siva Durga Prasad Paladugu45e512c2018-01-04 16:04:21 +053077#define ENABLE_ONDIE_ECC 0x08
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +053078
79#define ARASAN_PROG_RD_MASK 0x00000001
80#define ARASAN_PROG_BLK_ERS_MASK 0x00000004
81#define ARASAN_PROG_RD_ID_MASK 0x00000040
82#define ARASAN_PROG_RD_STS_MASK 0x00000008
83#define ARASAN_PROG_PG_PROG_MASK 0x00000010
84#define ARASAN_PROG_RD_PARAM_PG_MASK 0x00000080
85#define ARASAN_PROG_RST_MASK 0x00000100
86#define ARASAN_PROG_GET_FTRS_MASK 0x00000200
87#define ARASAN_PROG_SET_FTRS_MASK 0x00000400
88#define ARASAN_PROG_CHNG_ROWADR_END_MASK 0x00400000
89
90#define ARASAN_NAND_CMD_ECC_ON_MASK 0x80000000
91#define ARASAN_NAND_CMD_CMD12_MASK 0xFFFF
92#define ARASAN_NAND_CMD_PG_SIZE_MASK 0x3800000
93#define ARASAN_NAND_CMD_PG_SIZE_SHIFT 23
94#define ARASAN_NAND_CMD_CMD2_SHIFT 8
95#define ARASAN_NAND_CMD_ADDR_CYCL_MASK 0x70000000
96#define ARASAN_NAND_CMD_ADDR_CYCL_SHIFT 28
97
Vipul Kumar9d9b99b2018-03-10 17:52:23 +053098#define ARASAN_NAND_MEM_ADDR1_PAGE_MASK 0xFFFF0000
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +053099#define ARASAN_NAND_MEM_ADDR1_COL_MASK 0xFFFF
100#define ARASAN_NAND_MEM_ADDR1_PAGE_SHIFT 16
101#define ARASAN_NAND_MEM_ADDR2_PAGE_MASK 0xFF
102#define ARASAN_NAND_MEM_ADDR2_CS_MASK 0xC0000000
T Karthik Reddy7cd85222018-12-03 16:11:58 +0530103#define ARASAN_NAND_MEM_ADDR2_CS0_MASK (0x3 << 30)
104#define ARASAN_NAND_MEM_ADDR2_CS1_MASK (0x1 << 30)
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530105#define ARASAN_NAND_MEM_ADDR2_BCH_MASK 0xE000000
106#define ARASAN_NAND_MEM_ADDR2_BCH_SHIFT 25
107
108#define ARASAN_NAND_INT_STS_ERR_EN_MASK 0x10
109#define ARASAN_NAND_INT_STS_MUL_BIT_ERR_MASK 0x08
110#define ARASAN_NAND_INT_STS_BUF_RD_RDY_MASK 0x02
111#define ARASAN_NAND_INT_STS_BUF_WR_RDY_MASK 0x01
112#define ARASAN_NAND_INT_STS_XFR_CMPLT_MASK 0x04
113
114#define ARASAN_NAND_PKT_REG_PKT_CNT_MASK 0xFFF000
115#define ARASAN_NAND_PKT_REG_PKT_SIZE_MASK 0x7FF
116#define ARASAN_NAND_PKT_REG_PKT_CNT_SHFT 12
117
118#define ARASAN_NAND_ROW_ADDR_CYCL_MASK 0x0F
119#define ARASAN_NAND_COL_ADDR_CYCL_MASK 0xF0
120#define ARASAN_NAND_COL_ADDR_CYCL_SHIFT 4
121
122#define ARASAN_NAND_ECC_SIZE_SHIFT 16
123#define ARASAN_NAND_ECC_BCH_SHIFT 27
124
125#define ARASAN_NAND_PKTSIZE_1K 1024
126#define ARASAN_NAND_PKTSIZE_512 512
127
128#define ARASAN_NAND_POLL_TIMEOUT 1000000
129#define ARASAN_NAND_INVALID_ADDR_CYCL 0xFF
130
131#define ERR_ADDR_CYCLE -1
132#define READ_BUFF_SIZE 0x4000
133
134static struct arasan_nand_command_format *curr_cmd;
135
136enum addr_cycles {
137 NAND_ADDR_CYCL_NONE,
138 NAND_ADDR_CYCL_ONE,
139 NAND_ADDR_CYCL_ROW,
140 NAND_ADDR_CYCL_COL,
141 NAND_ADDR_CYCL_BOTH,
142};
143
144static struct arasan_nand_command_format arasan_nand_commands[] = {
145 {NAND_CMD_READ0, NAND_CMD_READSTART, NAND_ADDR_CYCL_BOTH,
146 ARASAN_PROG_RD_MASK},
147 {NAND_CMD_RNDOUT, NAND_CMD_RNDOUTSTART, NAND_ADDR_CYCL_COL,
148 ARASAN_PROG_RD_MASK},
149 {NAND_CMD_READID, NAND_CMD_NONE, NAND_ADDR_CYCL_ONE,
150 ARASAN_PROG_RD_ID_MASK},
151 {NAND_CMD_STATUS, NAND_CMD_NONE, NAND_ADDR_CYCL_NONE,
152 ARASAN_PROG_RD_STS_MASK},
153 {NAND_CMD_SEQIN, NAND_CMD_PAGEPROG, NAND_ADDR_CYCL_BOTH,
154 ARASAN_PROG_PG_PROG_MASK},
155 {NAND_CMD_RNDIN, NAND_CMD_NONE, NAND_ADDR_CYCL_COL,
156 ARASAN_PROG_CHNG_ROWADR_END_MASK},
157 {NAND_CMD_ERASE1, NAND_CMD_ERASE2, NAND_ADDR_CYCL_ROW,
158 ARASAN_PROG_BLK_ERS_MASK},
159 {NAND_CMD_RESET, NAND_CMD_NONE, NAND_ADDR_CYCL_NONE,
160 ARASAN_PROG_RST_MASK},
161 {NAND_CMD_PARAM, NAND_CMD_NONE, NAND_ADDR_CYCL_ONE,
162 ARASAN_PROG_RD_PARAM_PG_MASK},
163 {NAND_CMD_GET_FEATURES, NAND_CMD_NONE, NAND_ADDR_CYCL_ONE,
164 ARASAN_PROG_GET_FTRS_MASK},
165 {NAND_CMD_SET_FEATURES, NAND_CMD_NONE, NAND_ADDR_CYCL_ONE,
166 ARASAN_PROG_SET_FTRS_MASK},
167 {NAND_CMD_NONE, NAND_CMD_NONE, NAND_ADDR_CYCL_NONE, 0},
168};
169
170struct arasan_ecc_matrix {
171 u32 pagesize;
172 u32 ecc_codeword_size;
173 u8 eccbits;
174 u8 bch;
175 u8 bchval;
176 u16 eccaddr;
177 u16 eccsize;
178};
179
180static const struct arasan_ecc_matrix ecc_matrix[] = {
181 {512, 512, 1, 0, 0, 0x20D, 0x3},
182 {512, 512, 4, 1, 3, 0x209, 0x7},
183 {512, 512, 8, 1, 2, 0x203, 0xD},
184 /*
185 * 2K byte page
186 */
187 {2048, 512, 1, 0, 0, 0x834, 0xC},
188 {2048, 512, 4, 1, 3, 0x826, 0x1A},
189 {2048, 512, 8, 1, 2, 0x80c, 0x34},
190 {2048, 512, 12, 1, 1, 0x822, 0x4E},
191 {2048, 512, 16, 1, 0, 0x808, 0x68},
192 {2048, 1024, 24, 1, 4, 0x81c, 0x54},
193 /*
194 * 4K byte page
195 */
196 {4096, 512, 1, 0, 0, 0x1068, 0x18},
197 {4096, 512, 4, 1, 3, 0x104c, 0x34},
198 {4096, 512, 8, 1, 2, 0x1018, 0x68},
199 {4096, 512, 12, 1, 1, 0x1044, 0x9C},
200 {4096, 512, 16, 1, 0, 0x1010, 0xD0},
201 {4096, 1024, 24, 1, 4, 0x1038, 0xA8},
202 /*
203 * 8K byte page
204 */
205 {8192, 512, 1, 0, 0, 0x20d0, 0x30},
206 {8192, 512, 4, 1, 3, 0x2098, 0x68},
207 {8192, 512, 8, 1, 2, 0x2030, 0xD0},
208 {8192, 512, 12, 1, 1, 0x2088, 0x138},
209 {8192, 512, 16, 1, 0, 0x2020, 0x1A0},
210 {8192, 1024, 24, 1, 4, 0x2070, 0x150},
211 /*
212 * 16K byte page
213 */
214 {16384, 512, 1, 0, 0, 0x4460, 0x60},
215 {16384, 512, 4, 1, 3, 0x43f0, 0xD0},
216 {16384, 512, 8, 1, 2, 0x4320, 0x1A0},
217 {16384, 512, 12, 1, 1, 0x4250, 0x270},
218 {16384, 512, 16, 1, 0, 0x4180, 0x340},
219 {16384, 1024, 24, 1, 4, 0x4220, 0x2A0}
220};
221
Siva Durga Prasad Paladugu45e512c2018-01-04 16:04:21 +0530222static struct nand_ecclayout ondie_nand_oob_64 = {
223 .eccbytes = 32,
224
225 .eccpos = {
226 8, 9, 10, 11, 12, 13, 14, 15,
227 24, 25, 26, 27, 28, 29, 30, 31,
228 40, 41, 42, 43, 44, 45, 46, 47,
229 56, 57, 58, 59, 60, 61, 62, 63
230 },
231
232 .oobfree = {
233 { .offset = 4, .length = 4 },
234 { .offset = 20, .length = 4 },
235 { .offset = 36, .length = 4 },
236 { .offset = 52, .length = 4 }
237 }
238};
239
240/*
241 * bbt decriptors for chips with on-die ECC and
242 * chips with 64-byte OOB
243 */
244static u8 bbt_pattern[] = {'B', 'b', 't', '0' };
245static u8 mirror_pattern[] = {'1', 't', 'b', 'B' };
246
247static struct nand_bbt_descr bbt_main_descr = {
248 .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE |
249 NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
250 .offs = 4,
251 .len = 4,
252 .veroffs = 20,
253 .maxblocks = 4,
254 .pattern = bbt_pattern
255};
256
257static struct nand_bbt_descr bbt_mirror_descr = {
258 .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE |
259 NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
260 .offs = 4,
261 .len = 4,
262 .veroffs = 20,
263 .maxblocks = 4,
264 .pattern = mirror_pattern
265};
266
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530267static u8 buf_data[READ_BUFF_SIZE];
268static u32 buf_index;
269
270static struct nand_ecclayout nand_oob;
271
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530272static void arasan_nand_select_chip(struct mtd_info *mtd, int chip)
273{
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700274 struct nand_chip *nand_chip = mtd_to_nand(mtd);
275 struct nand_drv *info = nand_get_controller_data(nand_chip);
T Karthik Reddy7cd85222018-12-03 16:11:58 +0530276 u32 reg_val;
277
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700278 reg_val = readl(&info->reg->memadr_reg2);
T Karthik Reddy7cd85222018-12-03 16:11:58 +0530279 if (chip == 0) {
280 reg_val &= ~ARASAN_NAND_MEM_ADDR2_CS0_MASK;
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700281 writel(reg_val, &info->reg->memadr_reg2);
T Karthik Reddy7cd85222018-12-03 16:11:58 +0530282 } else if (chip == 1) {
283 reg_val |= ARASAN_NAND_MEM_ADDR2_CS1_MASK;
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700284 writel(reg_val, &info->reg->memadr_reg2);
T Karthik Reddy7cd85222018-12-03 16:11:58 +0530285 }
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530286}
287
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700288static void arasan_nand_enable_ecc(struct mtd_info *mtd)
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530289{
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700290 struct nand_chip *chip = mtd_to_nand(mtd);
291 struct nand_drv *info = nand_get_controller_data(chip);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530292 u32 reg_val;
293
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700294 reg_val = readl(&info->reg->cmd_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530295 reg_val |= ARASAN_NAND_CMD_ECC_ON_MASK;
296
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700297 writel(reg_val, &info->reg->cmd_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530298}
299
300static u8 arasan_nand_get_addrcycle(struct mtd_info *mtd)
301{
302 u8 addrcycles;
Scott Wood17fed142016-05-30 13:57:56 -0500303 struct nand_chip *chip = mtd_to_nand(mtd);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530304
305 switch (curr_cmd->addr_cycles) {
306 case NAND_ADDR_CYCL_NONE:
307 addrcycles = 0;
308 break;
309 case NAND_ADDR_CYCL_ONE:
310 addrcycles = 1;
311 break;
312 case NAND_ADDR_CYCL_ROW:
313 addrcycles = chip->onfi_params.addr_cycles &
314 ARASAN_NAND_ROW_ADDR_CYCL_MASK;
315 break;
316 case NAND_ADDR_CYCL_COL:
317 addrcycles = (chip->onfi_params.addr_cycles &
318 ARASAN_NAND_COL_ADDR_CYCL_MASK) >>
319 ARASAN_NAND_COL_ADDR_CYCL_SHIFT;
320 break;
321 case NAND_ADDR_CYCL_BOTH:
322 addrcycles = chip->onfi_params.addr_cycles &
323 ARASAN_NAND_ROW_ADDR_CYCL_MASK;
324 addrcycles += (chip->onfi_params.addr_cycles &
325 ARASAN_NAND_COL_ADDR_CYCL_MASK) >>
326 ARASAN_NAND_COL_ADDR_CYCL_SHIFT;
327 break;
328 default:
329 addrcycles = ARASAN_NAND_INVALID_ADDR_CYCL;
330 break;
331 }
332 return addrcycles;
333}
334
335static int arasan_nand_read_page(struct mtd_info *mtd, u8 *buf, u32 size)
336{
Scott Wood17fed142016-05-30 13:57:56 -0500337 struct nand_chip *chip = mtd_to_nand(mtd);
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700338 struct nand_drv *info = nand_get_controller_data(chip);
339 struct nand_config *nand = &info->config;
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530340 u32 reg_val, i, pktsize, pktnum;
341 u32 *bufptr = (u32 *)buf;
342 u32 timeout;
343 u32 rdcount = 0;
344 u8 addr_cycles;
345
346 if (chip->ecc_step_ds >= ARASAN_NAND_PKTSIZE_1K)
347 pktsize = ARASAN_NAND_PKTSIZE_1K;
348 else
349 pktsize = ARASAN_NAND_PKTSIZE_512;
350
351 if (size % pktsize)
352 pktnum = size/pktsize + 1;
353 else
354 pktnum = size/pktsize;
355
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700356 reg_val = readl(&info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530357 reg_val |= ARASAN_NAND_INT_STS_ERR_EN_MASK |
358 ARASAN_NAND_INT_STS_MUL_BIT_ERR_MASK;
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700359 writel(reg_val, &info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530360
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700361 reg_val = readl(&info->reg->pkt_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530362 reg_val &= ~(ARASAN_NAND_PKT_REG_PKT_CNT_MASK |
363 ARASAN_NAND_PKT_REG_PKT_SIZE_MASK);
364 reg_val |= (pktnum << ARASAN_NAND_PKT_REG_PKT_CNT_SHFT) |
365 pktsize;
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700366 writel(reg_val, &info->reg->pkt_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530367
Siva Durga Prasad Paladugu45e512c2018-01-04 16:04:21 +0530368 if (!nand->on_die_ecc_enabled) {
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700369 arasan_nand_enable_ecc(mtd);
Siva Durga Prasad Paladugu45e512c2018-01-04 16:04:21 +0530370 addr_cycles = arasan_nand_get_addrcycle(mtd);
371 if (addr_cycles == ARASAN_NAND_INVALID_ADDR_CYCL)
372 return ERR_ADDR_CYCLE;
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530373
Siva Durga Prasad Paladugu45e512c2018-01-04 16:04:21 +0530374 writel((NAND_CMD_RNDOUTSTART << ARASAN_NAND_CMD_CMD2_SHIFT) |
375 NAND_CMD_RNDOUT | (addr_cycles <<
376 ARASAN_NAND_CMD_ADDR_CYCL_SHIFT),
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700377 &info->reg->ecc_sprcmd_reg);
Siva Durga Prasad Paladugu45e512c2018-01-04 16:04:21 +0530378 }
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700379 writel(curr_cmd->pgm, &info->reg->pgm_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530380
381 while (rdcount < pktnum) {
382 timeout = ARASAN_NAND_POLL_TIMEOUT;
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700383 while (!(readl(&info->reg->intsts_reg) &
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530384 ARASAN_NAND_INT_STS_BUF_RD_RDY_MASK) && timeout) {
385 udelay(1);
386 timeout--;
387 }
388 if (!timeout) {
389 puts("arasan_read_page: timedout:Buff RDY\n");
390 return -ETIMEDOUT;
391 }
392
393 rdcount++;
394
395 if (pktnum == rdcount) {
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700396 reg_val = readl(&info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530397 reg_val |= ARASAN_NAND_INT_STS_XFR_CMPLT_MASK;
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700398 writel(reg_val, &info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530399 } else {
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700400 reg_val = readl(&info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530401 writel(reg_val | ARASAN_NAND_INT_STS_BUF_RD_RDY_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700402 &info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530403 }
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700404 reg_val = readl(&info->reg->intsts_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530405 writel(reg_val | ARASAN_NAND_INT_STS_BUF_RD_RDY_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700406 &info->reg->intsts_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530407
408 for (i = 0; i < pktsize/4; i++)
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700409 bufptr[i] = readl(&info->reg->buf_dataport);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530410
411
412 bufptr += pktsize/4;
413
414 if (rdcount >= pktnum)
415 break;
416
417 writel(ARASAN_NAND_INT_STS_BUF_RD_RDY_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700418 &info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530419 }
420
421 timeout = ARASAN_NAND_POLL_TIMEOUT;
422
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700423 while (!(readl(&info->reg->intsts_reg) &
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530424 ARASAN_NAND_INT_STS_XFR_CMPLT_MASK) && timeout) {
425 udelay(1);
426 timeout--;
427 }
428 if (!timeout) {
429 puts("arasan rd_page timedout:Xfer CMPLT\n");
430 return -ETIMEDOUT;
431 }
432
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700433 reg_val = readl(&info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530434 writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700435 &info->reg->intsts_enr);
436 reg_val = readl(&info->reg->intsts_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530437 writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700438 &info->reg->intsts_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530439
Siva Durga Prasad Paladugu45e512c2018-01-04 16:04:21 +0530440 if (!nand->on_die_ecc_enabled) {
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700441 if (readl(&info->reg->intsts_reg) &
Siva Durga Prasad Paladugu45e512c2018-01-04 16:04:21 +0530442 ARASAN_NAND_INT_STS_MUL_BIT_ERR_MASK) {
443 printf("arasan rd_page:sbiterror\n");
444 return -1;
445 }
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530446
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700447 if (readl(&info->reg->intsts_reg) &
Siva Durga Prasad Paladugu45e512c2018-01-04 16:04:21 +0530448 ARASAN_NAND_INT_STS_ERR_EN_MASK) {
449 mtd->ecc_stats.failed++;
450 printf("arasan rd_page:multibiterror\n");
451 return -1;
452 }
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530453 }
454
455 return 0;
456}
457
458static int arasan_nand_read_page_hwecc(struct mtd_info *mtd,
459 struct nand_chip *chip, u8 *buf, int oob_required, int page)
460{
461 int status;
462
463 status = arasan_nand_read_page(mtd, buf, (mtd->writesize));
464
465 if (oob_required)
466 chip->ecc.read_oob(mtd, chip, page);
467
468 return status;
469}
470
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700471static void arasan_nand_fill_tx(struct mtd_info *mtd, const u8 *buf, int len)
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530472{
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700473 struct nand_chip *chip = mtd_to_nand(mtd);
474 struct nand_drv *info = nand_get_controller_data(chip);
475 u32 __iomem *nand = &info->reg->buf_dataport;
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530476
477 if (((unsigned long)buf & 0x3) != 0) {
478 if (((unsigned long)buf & 0x1) != 0) {
479 if (len) {
480 writeb(*buf, nand);
481 buf += 1;
482 len--;
483 }
484 }
485
486 if (((unsigned long)buf & 0x3) != 0) {
487 if (len >= 2) {
488 writew(*(u16 *)buf, nand);
489 buf += 2;
490 len -= 2;
491 }
492 }
493 }
494
495 while (len >= 4) {
496 writel(*(u32 *)buf, nand);
497 buf += 4;
498 len -= 4;
499 }
500
501 if (len) {
502 if (len >= 2) {
503 writew(*(u16 *)buf, nand);
504 buf += 2;
505 len -= 2;
506 }
507
508 if (len)
509 writeb(*buf, nand);
510 }
511}
512
513static int arasan_nand_write_page_hwecc(struct mtd_info *mtd,
Scott Wood46e13102016-05-30 13:57:57 -0500514 struct nand_chip *chip, const u8 *buf, int oob_required,
515 int page)
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530516{
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700517 struct nand_drv *info = nand_get_controller_data(chip);
518 struct nand_config *nand = &info->config;
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530519 u32 reg_val, i, pktsize, pktnum;
520 const u32 *bufptr = (const u32 *)buf;
521 u32 timeout = ARASAN_NAND_POLL_TIMEOUT;
522 u32 size = mtd->writesize;
523 u32 rdcount = 0;
524 u8 column_addr_cycles;
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530525
526 if (chip->ecc_step_ds >= ARASAN_NAND_PKTSIZE_1K)
527 pktsize = ARASAN_NAND_PKTSIZE_1K;
528 else
529 pktsize = ARASAN_NAND_PKTSIZE_512;
530
531 if (size % pktsize)
532 pktnum = size/pktsize + 1;
533 else
534 pktnum = size/pktsize;
535
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700536 reg_val = readl(&info->reg->pkt_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530537 reg_val &= ~(ARASAN_NAND_PKT_REG_PKT_CNT_MASK |
538 ARASAN_NAND_PKT_REG_PKT_SIZE_MASK);
539 reg_val |= (pktnum << ARASAN_NAND_PKT_REG_PKT_CNT_SHFT) | pktsize;
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700540 writel(reg_val, &info->reg->pkt_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530541
Siva Durga Prasad Paladugu45e512c2018-01-04 16:04:21 +0530542 if (!nand->on_die_ecc_enabled) {
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700543 arasan_nand_enable_ecc(mtd);
Siva Durga Prasad Paladugu45e512c2018-01-04 16:04:21 +0530544 column_addr_cycles = (chip->onfi_params.addr_cycles &
545 ARASAN_NAND_COL_ADDR_CYCL_MASK) >>
546 ARASAN_NAND_COL_ADDR_CYCL_SHIFT;
547 writel((NAND_CMD_RNDIN | (column_addr_cycles << 28)),
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700548 &info->reg->ecc_sprcmd_reg);
Siva Durga Prasad Paladugu45e512c2018-01-04 16:04:21 +0530549 }
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700550 writel(curr_cmd->pgm, &info->reg->pgm_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530551
552 while (rdcount < pktnum) {
553 timeout = ARASAN_NAND_POLL_TIMEOUT;
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700554 while (!(readl(&info->reg->intsts_reg) &
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530555 ARASAN_NAND_INT_STS_BUF_WR_RDY_MASK) && timeout) {
556 udelay(1);
557 timeout--;
558 }
559
560 if (!timeout) {
561 puts("arasan_write_page: timedout:Buff RDY\n");
562 return -ETIMEDOUT;
563 }
564
565 rdcount++;
566
567 if (pktnum == rdcount) {
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700568 reg_val = readl(&info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530569 reg_val |= ARASAN_NAND_INT_STS_XFR_CMPLT_MASK;
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700570 writel(reg_val, &info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530571 } else {
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700572 reg_val = readl(&info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530573 writel(reg_val | ARASAN_NAND_INT_STS_BUF_WR_RDY_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700574 &info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530575 }
576
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700577 reg_val = readl(&info->reg->intsts_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530578 writel(reg_val | ARASAN_NAND_INT_STS_BUF_WR_RDY_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700579 &info->reg->intsts_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530580
581 for (i = 0; i < pktsize/4; i++)
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700582 writel(bufptr[i], &info->reg->buf_dataport);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530583
584 bufptr += pktsize/4;
585
586 if (rdcount >= pktnum)
587 break;
588
589 writel(ARASAN_NAND_INT_STS_BUF_WR_RDY_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700590 &info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530591 }
592
593 timeout = ARASAN_NAND_POLL_TIMEOUT;
594
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700595 while (!(readl(&info->reg->intsts_reg) &
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530596 ARASAN_NAND_INT_STS_XFR_CMPLT_MASK) && timeout) {
597 udelay(1);
598 timeout--;
599 }
600 if (!timeout) {
601 puts("arasan write_page timedout:Xfer CMPLT\n");
602 return -ETIMEDOUT;
603 }
604
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700605 reg_val = readl(&info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530606 writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700607 &info->reg->intsts_enr);
608 reg_val = readl(&info->reg->intsts_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530609 writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700610 &info->reg->intsts_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530611
612 if (oob_required)
613 chip->ecc.write_oob(mtd, chip, nand->page);
614
615 return 0;
616}
617
618static int arasan_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
619 int page)
620{
621 chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
622 chip->read_buf(mtd, chip->oob_poi, (mtd->oobsize));
623
624 return 0;
625}
626
627static int arasan_nand_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
628 int page)
629{
630 int status = 0;
631 const u8 *buf = chip->oob_poi;
632
633 chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page);
634 chip->write_buf(mtd, buf, mtd->oobsize);
635
636 return status;
637}
638
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700639static int arasan_nand_reset(struct mtd_info *mtd,
640 struct arasan_nand_command_format *curr_cmd)
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530641{
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700642 struct nand_chip *chip = mtd_to_nand(mtd);
643 struct nand_drv *info = nand_get_controller_data(chip);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530644 u32 timeout = ARASAN_NAND_POLL_TIMEOUT;
645 u32 cmd_reg = 0;
646
647 writel(ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700648 &info->reg->intsts_enr);
649 cmd_reg = readl(&info->reg->cmd_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530650 cmd_reg &= ~ARASAN_NAND_CMD_CMD12_MASK;
651
652 cmd_reg |= curr_cmd->cmd1 |
653 (curr_cmd->cmd2 << ARASAN_NAND_CMD_CMD2_SHIFT);
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700654 writel(cmd_reg, &info->reg->cmd_reg);
655 writel(curr_cmd->pgm, &info->reg->pgm_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530656
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700657 while (!(readl(&info->reg->intsts_reg) &
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530658 ARASAN_NAND_INT_STS_XFR_CMPLT_MASK) && timeout) {
659 udelay(1);
660 timeout--;
661 }
662 if (!timeout) {
663 printf("ERROR:%s timedout\n", __func__);
664 return -ETIMEDOUT;
665 }
666
667 writel(ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700668 &info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530669
670 writel(ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700671 &info->reg->intsts_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530672
673 return 0;
674}
675
676static u8 arasan_nand_page(struct mtd_info *mtd)
677{
678 u8 page_val = 0;
679
680 switch (mtd->writesize) {
681 case 512:
682 page_val = 0;
683 break;
684 case 2048:
685 page_val = 1;
686 break;
687 case 4096:
688 page_val = 2;
689 break;
690 case 8192:
691 page_val = 3;
692 break;
693 case 16384:
694 page_val = 4;
695 break;
696 case 1024:
697 page_val = 5;
698 break;
699 default:
700 printf("%s:Pagesize>16K\n", __func__);
701 break;
702 }
703
704 return page_val;
705}
706
707static int arasan_nand_send_wrcmd(struct arasan_nand_command_format *curr_cmd,
708 int column, int page_addr, struct mtd_info *mtd)
709{
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700710 struct nand_chip *chip = mtd_to_nand(mtd);
711 struct nand_drv *info = nand_get_controller_data(chip);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530712 u32 reg_val, page;
713 u8 page_val, addr_cycles;
714
715 writel(ARASAN_NAND_INT_STS_BUF_WR_RDY_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700716 &info->reg->intsts_enr);
717 reg_val = readl(&info->reg->cmd_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530718 reg_val &= ~ARASAN_NAND_CMD_CMD12_MASK;
719 reg_val |= curr_cmd->cmd1 |
720 (curr_cmd->cmd2 << ARASAN_NAND_CMD_CMD2_SHIFT);
721 if (curr_cmd->cmd1 == NAND_CMD_SEQIN) {
722 reg_val &= ~ARASAN_NAND_CMD_PG_SIZE_MASK;
723 page_val = arasan_nand_page(mtd);
724 reg_val |= (page_val << ARASAN_NAND_CMD_PG_SIZE_SHIFT);
725 }
726
727 reg_val &= ~ARASAN_NAND_CMD_ADDR_CYCL_MASK;
728 addr_cycles = arasan_nand_get_addrcycle(mtd);
729
730 if (addr_cycles == ARASAN_NAND_INVALID_ADDR_CYCL)
731 return ERR_ADDR_CYCLE;
732
733 reg_val |= (addr_cycles <<
734 ARASAN_NAND_CMD_ADDR_CYCL_SHIFT);
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700735 writel(reg_val, &info->reg->cmd_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530736
737 if (page_addr == -1)
738 page_addr = 0;
739
740 page = (page_addr << ARASAN_NAND_MEM_ADDR1_PAGE_SHIFT) &
741 ARASAN_NAND_MEM_ADDR1_PAGE_MASK;
742 column &= ARASAN_NAND_MEM_ADDR1_COL_MASK;
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700743 writel(page | column, &info->reg->memadr_reg1);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530744
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700745 reg_val = readl(&info->reg->memadr_reg2);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530746 reg_val &= ~ARASAN_NAND_MEM_ADDR2_PAGE_MASK;
747 reg_val |= (page_addr >> ARASAN_NAND_MEM_ADDR1_PAGE_SHIFT);
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700748 writel(reg_val, &info->reg->memadr_reg2);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530749
750 return 0;
751}
752
753static void arasan_nand_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
754{
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700755 struct nand_chip *chip = mtd_to_nand(mtd);
756 struct nand_drv *info = nand_get_controller_data(chip);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530757 u32 reg_val;
758 u32 timeout = ARASAN_NAND_POLL_TIMEOUT;
759
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700760 reg_val = readl(&info->reg->pkt_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530761 reg_val &= ~(ARASAN_NAND_PKT_REG_PKT_CNT_MASK |
762 ARASAN_NAND_PKT_REG_PKT_SIZE_MASK);
763
764 reg_val |= (1 << ARASAN_NAND_PKT_REG_PKT_CNT_SHFT) | len;
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700765 writel(reg_val, &info->reg->pkt_reg);
766 writel(curr_cmd->pgm, &info->reg->pgm_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530767
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700768 while (!(readl(&info->reg->intsts_reg) &
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530769 ARASAN_NAND_INT_STS_BUF_WR_RDY_MASK) && timeout) {
770 udelay(1);
771 timeout--;
772 }
773
774 if (!timeout)
775 puts("ERROR:arasan_nand_write_buf timedout:Buff RDY\n");
776
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700777 reg_val = readl(&info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530778 reg_val |= ARASAN_NAND_INT_STS_XFR_CMPLT_MASK;
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700779 writel(reg_val, &info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530780 writel(reg_val | ARASAN_NAND_INT_STS_BUF_WR_RDY_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700781 &info->reg->intsts_enr);
782 reg_val = readl(&info->reg->intsts_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530783 writel(reg_val | ARASAN_NAND_INT_STS_BUF_WR_RDY_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700784 &info->reg->intsts_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530785
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700786 arasan_nand_fill_tx(mtd, buf, len);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530787
788 timeout = ARASAN_NAND_POLL_TIMEOUT;
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700789 while (!(readl(&info->reg->intsts_reg) &
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530790 ARASAN_NAND_INT_STS_XFR_CMPLT_MASK) && timeout) {
791 udelay(1);
792 timeout--;
793 }
794 if (!timeout)
795 puts("ERROR:arasan_nand_write_buf timedout:Xfer CMPLT\n");
796
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700797 writel(readl(&info->reg->intsts_enr) |
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530798 ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700799 &info->reg->intsts_enr);
800 writel(readl(&info->reg->intsts_reg) |
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530801 ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700802 &info->reg->intsts_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530803}
804
805static int arasan_nand_erase(struct arasan_nand_command_format *curr_cmd,
806 int column, int page_addr, struct mtd_info *mtd)
807{
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700808 struct nand_chip *chip = mtd_to_nand(mtd);
809 struct nand_drv *info = nand_get_controller_data(chip);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530810 u32 reg_val, page;
811 u32 timeout = ARASAN_NAND_POLL_TIMEOUT;
812 u8 row_addr_cycles;
813
814 writel(ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700815 &info->reg->intsts_enr);
816 reg_val = readl(&info->reg->cmd_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530817 reg_val &= ~ARASAN_NAND_CMD_CMD12_MASK;
818 reg_val |= curr_cmd->cmd1 |
819 (curr_cmd->cmd2 << ARASAN_NAND_CMD_CMD2_SHIFT);
820 row_addr_cycles = arasan_nand_get_addrcycle(mtd);
821
822 if (row_addr_cycles == ARASAN_NAND_INVALID_ADDR_CYCL)
823 return ERR_ADDR_CYCLE;
824
825 reg_val &= ~ARASAN_NAND_CMD_ADDR_CYCL_MASK;
826 reg_val |= (row_addr_cycles <<
827 ARASAN_NAND_CMD_ADDR_CYCL_SHIFT);
828
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700829 writel(reg_val, &info->reg->cmd_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530830
Vipul Kumar673a5c22018-03-05 15:24:59 +0530831 page = (page_addr >> ARASAN_NAND_MEM_ADDR1_PAGE_SHIFT) &
Vipul Kumar9d9b99b2018-03-10 17:52:23 +0530832 ARASAN_NAND_MEM_ADDR1_COL_MASK;
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530833 column = page_addr & ARASAN_NAND_MEM_ADDR1_COL_MASK;
Vipul Kumar673a5c22018-03-05 15:24:59 +0530834 writel(column | (page << ARASAN_NAND_MEM_ADDR1_PAGE_SHIFT),
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700835 &info->reg->memadr_reg1);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530836
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700837 reg_val = readl(&info->reg->memadr_reg2);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530838 reg_val &= ~ARASAN_NAND_MEM_ADDR2_PAGE_MASK;
839 reg_val |= (page_addr >> ARASAN_NAND_MEM_ADDR1_PAGE_SHIFT);
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700840 writel(reg_val, &info->reg->memadr_reg2);
841 writel(curr_cmd->pgm, &info->reg->pgm_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530842
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700843 while (!(readl(&info->reg->intsts_reg) &
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530844 ARASAN_NAND_INT_STS_XFR_CMPLT_MASK) && timeout) {
845 udelay(1);
846 timeout--;
847 }
848 if (!timeout) {
849 printf("ERROR:%s timedout:Xfer CMPLT\n", __func__);
850 return -ETIMEDOUT;
851 }
852
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700853 reg_val = readl(&info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530854 writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700855 &info->reg->intsts_enr);
856 reg_val = readl(&info->reg->intsts_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530857 writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700858 &info->reg->intsts_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530859
860 return 0;
861}
862
863static int arasan_nand_read_status(struct arasan_nand_command_format *curr_cmd,
864 int column, int page_addr, struct mtd_info *mtd)
865{
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700866 struct nand_chip *chip = mtd_to_nand(mtd);
867 struct nand_drv *info = nand_get_controller_data(chip);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530868 u32 reg_val;
869 u32 timeout = ARASAN_NAND_POLL_TIMEOUT;
870 u8 addr_cycles;
871
872 writel(ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700873 &info->reg->intsts_enr);
874 reg_val = readl(&info->reg->cmd_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530875 reg_val &= ~ARASAN_NAND_CMD_CMD12_MASK;
876 reg_val |= curr_cmd->cmd1 |
877 (curr_cmd->cmd2 << ARASAN_NAND_CMD_CMD2_SHIFT);
878 addr_cycles = arasan_nand_get_addrcycle(mtd);
879
880 if (addr_cycles == ARASAN_NAND_INVALID_ADDR_CYCL)
881 return ERR_ADDR_CYCLE;
882
883 reg_val &= ~ARASAN_NAND_CMD_ADDR_CYCL_MASK;
884 reg_val |= (addr_cycles <<
885 ARASAN_NAND_CMD_ADDR_CYCL_SHIFT);
886
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700887 writel(reg_val, &info->reg->cmd_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530888
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700889 reg_val = readl(&info->reg->pkt_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530890 reg_val &= ~(ARASAN_NAND_PKT_REG_PKT_CNT_MASK |
891 ARASAN_NAND_PKT_REG_PKT_SIZE_MASK);
892 reg_val |= (1 << ARASAN_NAND_PKT_REG_PKT_CNT_SHFT) | 1;
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700893 writel(reg_val, &info->reg->pkt_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530894
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700895 writel(curr_cmd->pgm, &info->reg->pgm_reg);
896 while (!(readl(&info->reg->intsts_reg) &
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530897 ARASAN_NAND_INT_STS_XFR_CMPLT_MASK) && timeout) {
898 udelay(1);
899 timeout--;
900 }
901
902 if (!timeout) {
903 printf("ERROR:%s: timedout:Xfer CMPLT\n", __func__);
904 return -ETIMEDOUT;
905 }
906
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700907 reg_val = readl(&info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530908 writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700909 &info->reg->intsts_enr);
910 reg_val = readl(&info->reg->intsts_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530911 writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700912 &info->reg->intsts_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530913
914 return 0;
915}
916
917static int arasan_nand_send_rdcmd(struct arasan_nand_command_format *curr_cmd,
918 int column, int page_addr, struct mtd_info *mtd)
919{
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700920 struct nand_chip *chip = mtd_to_nand(mtd);
921 struct nand_drv *info = nand_get_controller_data(chip);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530922 u32 reg_val, addr_cycles, page;
923 u8 page_val;
924
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700925 reg_val = readl(&info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530926 writel(reg_val | ARASAN_NAND_INT_STS_BUF_RD_RDY_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700927 &info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530928
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700929 reg_val = readl(&info->reg->cmd_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530930 reg_val &= ~ARASAN_NAND_CMD_CMD12_MASK;
931 reg_val |= curr_cmd->cmd1 |
932 (curr_cmd->cmd2 << ARASAN_NAND_CMD_CMD2_SHIFT);
933
934 if (curr_cmd->cmd1 == NAND_CMD_RNDOUT ||
935 curr_cmd->cmd1 == NAND_CMD_READ0) {
936 reg_val &= ~ARASAN_NAND_CMD_PG_SIZE_MASK;
937 page_val = arasan_nand_page(mtd);
938 reg_val |= (page_val << ARASAN_NAND_CMD_PG_SIZE_SHIFT);
939 }
940
Siva Durga Prasad Paladugu99459c22016-08-25 16:00:04 +0530941 reg_val &= ~ARASAN_NAND_CMD_ECC_ON_MASK;
942
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530943 reg_val &= ~ARASAN_NAND_CMD_ADDR_CYCL_MASK;
944
945 addr_cycles = arasan_nand_get_addrcycle(mtd);
946
947 if (addr_cycles == ARASAN_NAND_INVALID_ADDR_CYCL)
948 return ERR_ADDR_CYCLE;
949
950 reg_val |= (addr_cycles << 28);
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700951 writel(reg_val, &info->reg->cmd_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530952
953 if (page_addr == -1)
954 page_addr = 0;
955
956 page = (page_addr << ARASAN_NAND_MEM_ADDR1_PAGE_SHIFT) &
957 ARASAN_NAND_MEM_ADDR1_PAGE_MASK;
958 column &= ARASAN_NAND_MEM_ADDR1_COL_MASK;
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700959 writel(page | column, &info->reg->memadr_reg1);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530960
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700961 reg_val = readl(&info->reg->memadr_reg2);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530962 reg_val &= ~ARASAN_NAND_MEM_ADDR2_PAGE_MASK;
963 reg_val |= (page_addr >> ARASAN_NAND_MEM_ADDR1_PAGE_SHIFT);
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700964 writel(reg_val, &info->reg->memadr_reg2);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530965
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530966 buf_index = 0;
967
968 return 0;
969}
970
971static void arasan_nand_read_buf(struct mtd_info *mtd, u8 *buf, int size)
972{
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700973 struct nand_chip *chip = mtd_to_nand(mtd);
974 struct nand_drv *info = nand_get_controller_data(chip);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530975 u32 reg_val, i;
976 u32 *bufptr = (u32 *)buf;
977 u32 timeout = ARASAN_NAND_POLL_TIMEOUT;
978
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700979 reg_val = readl(&info->reg->pkt_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530980 reg_val &= ~(ARASAN_NAND_PKT_REG_PKT_CNT_MASK |
981 ARASAN_NAND_PKT_REG_PKT_SIZE_MASK);
982 reg_val |= (1 << ARASAN_NAND_PKT_REG_PKT_CNT_SHFT) | size;
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700983 writel(reg_val, &info->reg->pkt_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530984
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700985 writel(curr_cmd->pgm, &info->reg->pgm_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530986
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700987 while (!(readl(&info->reg->intsts_reg) &
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530988 ARASAN_NAND_INT_STS_BUF_RD_RDY_MASK) && timeout) {
989 udelay(1);
990 timeout--;
991 }
992
993 if (!timeout)
994 puts("ERROR:arasan_nand_read_buf timedout:Buff RDY\n");
995
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700996 reg_val = readl(&info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530997 reg_val |= ARASAN_NAND_INT_STS_XFR_CMPLT_MASK;
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700998 writel(reg_val, &info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530999
1000 writel(reg_val | ARASAN_NAND_INT_STS_BUF_RD_RDY_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -07001001 &info->reg->intsts_enr);
1002 reg_val = readl(&info->reg->intsts_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301003 writel(reg_val | ARASAN_NAND_INT_STS_BUF_RD_RDY_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -07001004 &info->reg->intsts_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301005
1006 buf_index = 0;
1007 for (i = 0; i < size / 4; i++)
Ashok Reddy Soma13e92302019-12-19 02:27:43 -07001008 bufptr[i] = readl(&info->reg->buf_dataport);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301009
1010 if (size & 0x03)
Ashok Reddy Soma13e92302019-12-19 02:27:43 -07001011 bufptr[i] = readl(&info->reg->buf_dataport);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301012
1013 timeout = ARASAN_NAND_POLL_TIMEOUT;
1014
Ashok Reddy Soma13e92302019-12-19 02:27:43 -07001015 while (!(readl(&info->reg->intsts_reg) &
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301016 ARASAN_NAND_INT_STS_XFR_CMPLT_MASK) && timeout) {
1017 udelay(1);
1018 timeout--;
1019 }
1020
1021 if (!timeout)
1022 puts("ERROR:arasan_nand_read_buf timedout:Xfer CMPLT\n");
1023
Ashok Reddy Soma13e92302019-12-19 02:27:43 -07001024 reg_val = readl(&info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301025 writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -07001026 &info->reg->intsts_enr);
1027 reg_val = readl(&info->reg->intsts_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301028 writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -07001029 &info->reg->intsts_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301030}
1031
1032static u8 arasan_nand_read_byte(struct mtd_info *mtd)
1033{
Scott Wood17fed142016-05-30 13:57:56 -05001034 struct nand_chip *chip = mtd_to_nand(mtd);
Ashok Reddy Soma13e92302019-12-19 02:27:43 -07001035 struct nand_drv *info = nand_get_controller_data(chip);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301036 u32 size;
1037 u8 val;
1038 struct nand_onfi_params *p;
1039
1040 if (buf_index == 0) {
1041 p = &chip->onfi_params;
1042 if (curr_cmd->cmd1 == NAND_CMD_READID)
1043 size = 4;
1044 else if (curr_cmd->cmd1 == NAND_CMD_PARAM)
1045 size = sizeof(struct nand_onfi_params);
1046 else if (curr_cmd->cmd1 == NAND_CMD_RNDOUT)
1047 size = le16_to_cpu(p->ext_param_page_length) * 16;
1048 else if (curr_cmd->cmd1 == NAND_CMD_GET_FEATURES)
1049 size = 4;
1050 else if (curr_cmd->cmd1 == NAND_CMD_STATUS)
Ashok Reddy Soma13e92302019-12-19 02:27:43 -07001051 return readb(&info->reg->flash_sts_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301052 else
1053 size = 8;
1054 chip->read_buf(mtd, &buf_data[0], size);
1055 }
1056
1057 val = *(&buf_data[0] + buf_index);
1058 buf_index++;
1059
1060 return val;
1061}
1062
1063static void arasan_nand_cmd_function(struct mtd_info *mtd, unsigned int command,
1064 int column, int page_addr)
1065{
Scott Wood17fed142016-05-30 13:57:56 -05001066 struct nand_chip *chip = mtd_to_nand(mtd);
Ashok Reddy Soma13e92302019-12-19 02:27:43 -07001067 struct nand_drv *info = nand_get_controller_data(chip);
1068 struct nand_config *nand = &info->config;
1069 u32 i, ret = 0;
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301070
1071 curr_cmd = NULL;
1072 writel(ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -07001073 &info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301074
1075 if ((command == NAND_CMD_READOOB) &&
1076 (mtd->writesize > 512)) {
1077 column += mtd->writesize;
1078 command = NAND_CMD_READ0;
1079 }
1080
1081 /* Get the command format */
1082 for (i = 0; (arasan_nand_commands[i].cmd1 != NAND_CMD_NONE ||
1083 arasan_nand_commands[i].cmd2 != NAND_CMD_NONE); i++) {
1084 if (command == arasan_nand_commands[i].cmd1) {
1085 curr_cmd = &arasan_nand_commands[i];
1086 break;
1087 }
1088 }
1089
1090 if (curr_cmd == NULL) {
1091 printf("Unsupported Command; 0x%x\n", command);
1092 return;
1093 }
1094
1095 if (curr_cmd->cmd1 == NAND_CMD_RESET)
Ashok Reddy Soma13e92302019-12-19 02:27:43 -07001096 ret = arasan_nand_reset(mtd, curr_cmd);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301097
1098 if ((curr_cmd->cmd1 == NAND_CMD_READID) ||
1099 (curr_cmd->cmd1 == NAND_CMD_PARAM) ||
1100 (curr_cmd->cmd1 == NAND_CMD_RNDOUT) ||
1101 (curr_cmd->cmd1 == NAND_CMD_GET_FEATURES) ||
1102 (curr_cmd->cmd1 == NAND_CMD_READ0))
1103 ret = arasan_nand_send_rdcmd(curr_cmd, column, page_addr, mtd);
1104
1105 if ((curr_cmd->cmd1 == NAND_CMD_SET_FEATURES) ||
1106 (curr_cmd->cmd1 == NAND_CMD_SEQIN)) {
1107 nand->page = page_addr;
1108 ret = arasan_nand_send_wrcmd(curr_cmd, column, page_addr, mtd);
1109 }
1110
1111 if (curr_cmd->cmd1 == NAND_CMD_ERASE1)
1112 ret = arasan_nand_erase(curr_cmd, column, page_addr, mtd);
1113
1114 if (curr_cmd->cmd1 == NAND_CMD_STATUS)
1115 ret = arasan_nand_read_status(curr_cmd, column, page_addr, mtd);
1116
1117 if (ret != 0)
1118 printf("ERROR:%s:command:0x%x\n", __func__, curr_cmd->cmd1);
1119}
1120
Siva Durga Prasad Paladugu45e512c2018-01-04 16:04:21 +05301121static void arasan_check_ondie(struct mtd_info *mtd)
1122{
1123 struct nand_chip *nand_chip = mtd_to_nand(mtd);
T Karthik Reddy4de4f382020-01-19 23:59:23 -07001124 struct nand_drv *info = nand_get_controller_data(nand_chip);
1125 struct nand_config *nand = &info->config;
Siva Durga Prasad Paladugu45e512c2018-01-04 16:04:21 +05301126 u8 maf_id, dev_id;
1127 u8 get_feature[4];
1128 u8 set_feature[4] = {ENABLE_ONDIE_ECC, 0x00, 0x00, 0x00};
1129 u32 i;
1130
T Karthik Reddy4de4f382020-01-19 23:59:23 -07001131 nand_chip->select_chip(mtd, 0);
1132
Siva Durga Prasad Paladugu45e512c2018-01-04 16:04:21 +05301133 /* Send the command for reading device ID */
1134 nand_chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
1135 nand_chip->cmdfunc(mtd, NAND_CMD_READID, 0, -1);
1136
1137 /* Read manufacturer and device IDs */
1138 maf_id = nand_chip->read_byte(mtd);
1139 dev_id = nand_chip->read_byte(mtd);
1140
1141 if ((maf_id == NAND_MFR_MICRON) &&
1142 ((dev_id == 0xf1) || (dev_id == 0xa1) || (dev_id == 0xb1) ||
1143 (dev_id == 0xaa) || (dev_id == 0xba) || (dev_id == 0xda) ||
1144 (dev_id == 0xca) || (dev_id == 0xac) || (dev_id == 0xbc) ||
1145 (dev_id == 0xdc) || (dev_id == 0xcc) || (dev_id == 0xa3) ||
1146 (dev_id == 0xb3) || (dev_id == 0xd3) || (dev_id == 0xc3))) {
1147 nand_chip->cmdfunc(mtd, NAND_CMD_SET_FEATURES,
1148 ONDIE_ECC_FEATURE_ADDR, -1);
1149
1150 nand_chip->write_buf(mtd, &set_feature[0], 4);
1151 nand_chip->cmdfunc(mtd, NAND_CMD_GET_FEATURES,
1152 ONDIE_ECC_FEATURE_ADDR, -1);
1153
1154 for (i = 0; i < 4; i++)
1155 get_feature[i] = nand_chip->read_byte(mtd);
1156
T Karthik Reddy4de4f382020-01-19 23:59:23 -07001157 if (get_feature[0] & ENABLE_ONDIE_ECC) {
Siva Durga Prasad Paladugu45e512c2018-01-04 16:04:21 +05301158 nand->on_die_ecc_enabled = true;
T Karthik Reddy4de4f382020-01-19 23:59:23 -07001159 printf("On-DIE ECC Enabled\n");
1160 } else {
Siva Durga Prasad Paladugu45e512c2018-01-04 16:04:21 +05301161 printf("%s: Unable to enable OnDie ECC\n", __func__);
T Karthik Reddy4de4f382020-01-19 23:59:23 -07001162 }
Siva Durga Prasad Paladugu45e512c2018-01-04 16:04:21 +05301163
1164 /* Use the BBT pattern descriptors */
1165 nand_chip->bbt_td = &bbt_main_descr;
1166 nand_chip->bbt_md = &bbt_mirror_descr;
1167 }
1168}
1169
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301170static int arasan_nand_ecc_init(struct mtd_info *mtd)
1171{
Ashok Reddy Soma13e92302019-12-19 02:27:43 -07001172 struct nand_chip *nand_chip = mtd_to_nand(mtd);
1173 struct nand_drv *info = nand_get_controller_data(nand_chip);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301174 int found = -1;
Siva Durga Prasad Paladugub0a4f132018-01-04 16:04:22 +05301175 u32 regval, eccpos_start, i, eccaddr;
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301176
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301177 for (i = 0; i < ARRAY_SIZE(ecc_matrix); i++) {
1178 if ((ecc_matrix[i].pagesize == mtd->writesize) &&
1179 (ecc_matrix[i].ecc_codeword_size >=
1180 nand_chip->ecc_step_ds)) {
1181 if (ecc_matrix[i].eccbits >=
1182 nand_chip->ecc_strength_ds) {
1183 found = i;
1184 break;
1185 }
1186 found = i;
1187 }
1188 }
1189
1190 if (found < 0)
1191 return 1;
1192
Siva Durga Prasad Paladugub0a4f132018-01-04 16:04:22 +05301193 eccaddr = mtd->writesize + mtd->oobsize -
1194 ecc_matrix[found].eccsize;
1195
1196 regval = eccaddr |
Siva Durga Prasad Paladugudb796632016-05-25 15:20:38 +05301197 (ecc_matrix[found].eccsize << ARASAN_NAND_ECC_SIZE_SHIFT) |
1198 (ecc_matrix[found].bch << ARASAN_NAND_ECC_BCH_SHIFT);
Ashok Reddy Soma13e92302019-12-19 02:27:43 -07001199 writel(regval, &info->reg->ecc_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301200
Siva Durga Prasad Paladugudb796632016-05-25 15:20:38 +05301201 if (ecc_matrix[found].bch) {
Ashok Reddy Soma13e92302019-12-19 02:27:43 -07001202 regval = readl(&info->reg->memadr_reg2);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301203 regval &= ~ARASAN_NAND_MEM_ADDR2_BCH_MASK;
Siva Durga Prasad Paladugudb796632016-05-25 15:20:38 +05301204 regval |= (ecc_matrix[found].bchval <<
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301205 ARASAN_NAND_MEM_ADDR2_BCH_SHIFT);
Ashok Reddy Soma13e92302019-12-19 02:27:43 -07001206 writel(regval, &info->reg->memadr_reg2);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301207 }
1208
Siva Durga Prasad Paladugudb796632016-05-25 15:20:38 +05301209 nand_oob.eccbytes = ecc_matrix[found].eccsize;
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301210 eccpos_start = mtd->oobsize - nand_oob.eccbytes;
1211
1212 for (i = 0; i < nand_oob.eccbytes; i++)
1213 nand_oob.eccpos[i] = eccpos_start + i;
1214
1215 nand_oob.oobfree[0].offset = 2;
1216 nand_oob.oobfree[0].length = eccpos_start - 2;
1217
Siva Durga Prasad Paladugudb796632016-05-25 15:20:38 +05301218 nand_chip->ecc.size = ecc_matrix[found].ecc_codeword_size;
1219 nand_chip->ecc.strength = ecc_matrix[found].eccbits;
1220 nand_chip->ecc.bytes = ecc_matrix[found].eccsize;
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301221 nand_chip->ecc.layout = &nand_oob;
1222
1223 return 0;
1224}
1225
Ashok Reddy Somac7b66332019-12-19 02:27:42 -07001226static int arasan_probe(struct udevice *dev)
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301227{
Ashok Reddy Somac7b66332019-12-19 02:27:42 -07001228 struct arasan_nand_info *arasan = dev_get_priv(dev);
1229 struct nand_chip *nand_chip = &arasan->nand_chip;
Ashok Reddy Soma13e92302019-12-19 02:27:43 -07001230 struct nand_drv *info = &arasan->nand_ctrl;
1231 struct nand_config *nand = &info->config;
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301232 struct mtd_info *mtd;
Ashok Reddy Somaaf1d3cf2023-02-23 22:07:07 -07001233 ofnode child;
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301234 int err = -1;
1235
Johan Jonker8d5d8e02023-03-13 01:32:04 +01001236 info->reg = dev_read_addr_ptr(dev);
Scott Wood17fed142016-05-30 13:57:56 -05001237 mtd = nand_to_mtd(nand_chip);
Ashok Reddy Soma13e92302019-12-19 02:27:43 -07001238 nand_set_controller_data(nand_chip, &arasan->nand_ctrl);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301239
Ashok Reddy Somaaf1d3cf2023-02-23 22:07:07 -07001240 ofnode_for_each_subnode(child, dev_ofnode(dev))
1241 nand_set_flash_node(nand_chip, child);
1242
Martin Lund5f9ae0e2018-10-30 14:16:19 +01001243#ifdef CONFIG_SYS_NAND_NO_SUBPAGE_WRITE
1244 nand_chip->options |= NAND_NO_SUBPAGE_WRITE;
1245#endif
1246
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301247 /* Set the driver entry points for MTD */
1248 nand_chip->cmdfunc = arasan_nand_cmd_function;
1249 nand_chip->select_chip = arasan_nand_select_chip;
1250 nand_chip->read_byte = arasan_nand_read_byte;
1251
1252 /* Buffer read/write routines */
1253 nand_chip->read_buf = arasan_nand_read_buf;
1254 nand_chip->write_buf = arasan_nand_write_buf;
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301255
Ashok Reddy Soma13e92302019-12-19 02:27:43 -07001256 writel(0x0, &info->reg->cmd_reg);
1257 writel(0x0, &info->reg->pgm_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301258
1259 /* first scan to find the device and get the page size */
T Karthik Reddy7cd85222018-12-03 16:11:58 +05301260 if (nand_scan_ident(mtd, CONFIG_SYS_NAND_MAX_CHIPS, NULL)) {
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301261 printf("%s: nand_scan_ident failed\n", __func__);
1262 goto fail;
1263 }
1264
Siva Durga Prasad Paladugu80c889c2018-01-04 16:04:20 +05301265 nand_chip->ecc.mode = NAND_ECC_HW;
1266 nand_chip->ecc.hwctl = NULL;
1267 nand_chip->ecc.read_page = arasan_nand_read_page_hwecc;
1268 nand_chip->ecc.write_page = arasan_nand_write_page_hwecc;
1269 nand_chip->ecc.read_oob = arasan_nand_read_oob;
1270 nand_chip->ecc.write_oob = arasan_nand_write_oob;
1271
Siva Durga Prasad Paladugu45e512c2018-01-04 16:04:21 +05301272 arasan_check_ondie(mtd);
1273
1274 /*
1275 * If on die supported, then give priority to on-die ecc and use
1276 * it instead of controller ecc.
1277 */
1278 if (nand->on_die_ecc_enabled) {
1279 nand_chip->ecc.strength = 1;
1280 nand_chip->ecc.size = mtd->writesize;
1281 nand_chip->ecc.bytes = 0;
1282 nand_chip->ecc.layout = &ondie_nand_oob_64;
1283 } else {
1284 if (arasan_nand_ecc_init(mtd)) {
1285 printf("%s: nand_ecc_init failed\n", __func__);
1286 goto fail;
1287 }
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301288 }
1289
1290 if (nand_scan_tail(mtd)) {
1291 printf("%s: nand_scan_tail failed\n", __func__);
1292 goto fail;
1293 }
1294
Ashok Reddy Somac7b66332019-12-19 02:27:42 -07001295 if (nand_register(0, mtd)) {
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301296 printf("Nand Register Fail\n");
1297 goto fail;
1298 }
1299
1300 return 0;
1301fail:
1302 free(nand);
1303 return err;
1304}
1305
Ashok Reddy Somac7b66332019-12-19 02:27:42 -07001306static const struct udevice_id arasan_nand_dt_ids[] = {
1307 {.compatible = "arasan,nfc-v3p10",},
1308 { /* sentinel */ }
1309};
1310
1311U_BOOT_DRIVER(arasan_nand) = {
Michal Simek33093082020-01-07 08:50:34 +01001312 .name = "arasan_nand",
Ashok Reddy Somac7b66332019-12-19 02:27:42 -07001313 .id = UCLASS_MTD,
1314 .of_match = arasan_nand_dt_ids,
1315 .probe = arasan_probe,
Simon Glass8a2b47f2020-12-03 16:55:17 -07001316 .priv_auto = sizeof(struct arasan_nand_info),
Ashok Reddy Somac7b66332019-12-19 02:27:42 -07001317};
1318
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301319void board_nand_init(void)
1320{
Ashok Reddy Somac7b66332019-12-19 02:27:42 -07001321 struct udevice *dev;
1322 int ret;
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301323
Ashok Reddy Somac7b66332019-12-19 02:27:42 -07001324 ret = uclass_get_device_by_driver(UCLASS_MTD,
Simon Glass65130cd2020-12-28 20:34:56 -07001325 DM_DRIVER_GET(arasan_nand), &dev);
Ashok Reddy Somac7b66332019-12-19 02:27:42 -07001326 if (ret && ret != -ENODEV)
1327 pr_err("Failed to initialize %s. (error %d)\n", dev->name, ret);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301328}