blob: 10596ce8ee02c64469b12e2954b8e9ccd4ebdeb8 [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
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05308#include <malloc.h>
9#include <asm/io.h>
Simon Glassdbd79542020-05-10 11:40:11 -060010#include <linux/delay.h>
Masahiro Yamada56a931c2016-09-21 11:28:55 +090011#include <linux/errno.h>
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +053012#include <linux/mtd/mtd.h>
Masahiro Yamada2b7a8732017-11-30 13:45:24 +090013#include <linux/mtd/rawnand.h>
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +053014#include <linux/mtd/partitions.h>
15#include <linux/mtd/nand_ecc.h>
16#include <asm/arch/hardware.h>
17#include <asm/arch/sys_proto.h>
Ashok Reddy Somac7b66332019-12-19 02:27:42 -070018#include <dm.h>
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +053019#include <nand.h>
Simon Glassbdd5f812023-09-14 18:21:46 -060020#include <linux/printk.h>
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +053021
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
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530411 bufptr += pktsize/4;
412
413 if (rdcount >= pktnum)
414 break;
415
416 writel(ARASAN_NAND_INT_STS_BUF_RD_RDY_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700417 &info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530418 }
419
420 timeout = ARASAN_NAND_POLL_TIMEOUT;
421
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700422 while (!(readl(&info->reg->intsts_reg) &
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530423 ARASAN_NAND_INT_STS_XFR_CMPLT_MASK) && timeout) {
424 udelay(1);
425 timeout--;
426 }
427 if (!timeout) {
428 puts("arasan rd_page timedout:Xfer CMPLT\n");
429 return -ETIMEDOUT;
430 }
431
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700432 reg_val = readl(&info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530433 writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700434 &info->reg->intsts_enr);
435 reg_val = readl(&info->reg->intsts_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530436 writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700437 &info->reg->intsts_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530438
Siva Durga Prasad Paladugu45e512c2018-01-04 16:04:21 +0530439 if (!nand->on_die_ecc_enabled) {
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700440 if (readl(&info->reg->intsts_reg) &
Siva Durga Prasad Paladugu45e512c2018-01-04 16:04:21 +0530441 ARASAN_NAND_INT_STS_MUL_BIT_ERR_MASK) {
442 printf("arasan rd_page:sbiterror\n");
443 return -1;
444 }
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530445
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700446 if (readl(&info->reg->intsts_reg) &
Siva Durga Prasad Paladugu45e512c2018-01-04 16:04:21 +0530447 ARASAN_NAND_INT_STS_ERR_EN_MASK) {
448 mtd->ecc_stats.failed++;
449 printf("arasan rd_page:multibiterror\n");
450 return -1;
451 }
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530452 }
453
454 return 0;
455}
456
457static int arasan_nand_read_page_hwecc(struct mtd_info *mtd,
458 struct nand_chip *chip, u8 *buf, int oob_required, int page)
459{
460 int status;
461
462 status = arasan_nand_read_page(mtd, buf, (mtd->writesize));
463
464 if (oob_required)
465 chip->ecc.read_oob(mtd, chip, page);
466
467 return status;
468}
469
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700470static void arasan_nand_fill_tx(struct mtd_info *mtd, const u8 *buf, int len)
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530471{
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700472 struct nand_chip *chip = mtd_to_nand(mtd);
473 struct nand_drv *info = nand_get_controller_data(chip);
474 u32 __iomem *nand = &info->reg->buf_dataport;
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530475
476 if (((unsigned long)buf & 0x3) != 0) {
477 if (((unsigned long)buf & 0x1) != 0) {
478 if (len) {
479 writeb(*buf, nand);
480 buf += 1;
481 len--;
482 }
483 }
484
485 if (((unsigned long)buf & 0x3) != 0) {
486 if (len >= 2) {
487 writew(*(u16 *)buf, nand);
488 buf += 2;
489 len -= 2;
490 }
491 }
492 }
493
494 while (len >= 4) {
495 writel(*(u32 *)buf, nand);
496 buf += 4;
497 len -= 4;
498 }
499
500 if (len) {
501 if (len >= 2) {
502 writew(*(u16 *)buf, nand);
503 buf += 2;
504 len -= 2;
505 }
506
507 if (len)
508 writeb(*buf, nand);
509 }
510}
511
512static int arasan_nand_write_page_hwecc(struct mtd_info *mtd,
Scott Wood46e13102016-05-30 13:57:57 -0500513 struct nand_chip *chip, const u8 *buf, int oob_required,
514 int page)
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530515{
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700516 struct nand_drv *info = nand_get_controller_data(chip);
517 struct nand_config *nand = &info->config;
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530518 u32 reg_val, i, pktsize, pktnum;
519 const u32 *bufptr = (const u32 *)buf;
520 u32 timeout = ARASAN_NAND_POLL_TIMEOUT;
521 u32 size = mtd->writesize;
522 u32 rdcount = 0;
523 u8 column_addr_cycles;
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530524
525 if (chip->ecc_step_ds >= ARASAN_NAND_PKTSIZE_1K)
526 pktsize = ARASAN_NAND_PKTSIZE_1K;
527 else
528 pktsize = ARASAN_NAND_PKTSIZE_512;
529
530 if (size % pktsize)
531 pktnum = size/pktsize + 1;
532 else
533 pktnum = size/pktsize;
534
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700535 reg_val = readl(&info->reg->pkt_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530536 reg_val &= ~(ARASAN_NAND_PKT_REG_PKT_CNT_MASK |
537 ARASAN_NAND_PKT_REG_PKT_SIZE_MASK);
538 reg_val |= (pktnum << ARASAN_NAND_PKT_REG_PKT_CNT_SHFT) | pktsize;
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700539 writel(reg_val, &info->reg->pkt_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530540
Siva Durga Prasad Paladugu45e512c2018-01-04 16:04:21 +0530541 if (!nand->on_die_ecc_enabled) {
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700542 arasan_nand_enable_ecc(mtd);
Siva Durga Prasad Paladugu45e512c2018-01-04 16:04:21 +0530543 column_addr_cycles = (chip->onfi_params.addr_cycles &
544 ARASAN_NAND_COL_ADDR_CYCL_MASK) >>
545 ARASAN_NAND_COL_ADDR_CYCL_SHIFT;
546 writel((NAND_CMD_RNDIN | (column_addr_cycles << 28)),
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700547 &info->reg->ecc_sprcmd_reg);
Siva Durga Prasad Paladugu45e512c2018-01-04 16:04:21 +0530548 }
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700549 writel(curr_cmd->pgm, &info->reg->pgm_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530550
551 while (rdcount < pktnum) {
552 timeout = ARASAN_NAND_POLL_TIMEOUT;
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700553 while (!(readl(&info->reg->intsts_reg) &
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530554 ARASAN_NAND_INT_STS_BUF_WR_RDY_MASK) && timeout) {
555 udelay(1);
556 timeout--;
557 }
558
559 if (!timeout) {
560 puts("arasan_write_page: timedout:Buff RDY\n");
561 return -ETIMEDOUT;
562 }
563
564 rdcount++;
565
566 if (pktnum == rdcount) {
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700567 reg_val = readl(&info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530568 reg_val |= ARASAN_NAND_INT_STS_XFR_CMPLT_MASK;
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700569 writel(reg_val, &info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530570 } else {
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700571 reg_val = readl(&info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530572 writel(reg_val | ARASAN_NAND_INT_STS_BUF_WR_RDY_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700573 &info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530574 }
575
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700576 reg_val = readl(&info->reg->intsts_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530577 writel(reg_val | ARASAN_NAND_INT_STS_BUF_WR_RDY_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700578 &info->reg->intsts_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530579
580 for (i = 0; i < pktsize/4; i++)
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700581 writel(bufptr[i], &info->reg->buf_dataport);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530582
583 bufptr += pktsize/4;
584
585 if (rdcount >= pktnum)
586 break;
587
588 writel(ARASAN_NAND_INT_STS_BUF_WR_RDY_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700589 &info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530590 }
591
592 timeout = ARASAN_NAND_POLL_TIMEOUT;
593
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700594 while (!(readl(&info->reg->intsts_reg) &
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530595 ARASAN_NAND_INT_STS_XFR_CMPLT_MASK) && timeout) {
596 udelay(1);
597 timeout--;
598 }
599 if (!timeout) {
600 puts("arasan write_page timedout:Xfer CMPLT\n");
601 return -ETIMEDOUT;
602 }
603
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700604 reg_val = readl(&info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530605 writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700606 &info->reg->intsts_enr);
607 reg_val = readl(&info->reg->intsts_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530608 writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700609 &info->reg->intsts_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530610
611 if (oob_required)
612 chip->ecc.write_oob(mtd, chip, nand->page);
613
614 return 0;
615}
616
617static int arasan_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
618 int page)
619{
620 chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
621 chip->read_buf(mtd, chip->oob_poi, (mtd->oobsize));
622
623 return 0;
624}
625
626static int arasan_nand_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
627 int page)
628{
629 int status = 0;
630 const u8 *buf = chip->oob_poi;
631
632 chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page);
633 chip->write_buf(mtd, buf, mtd->oobsize);
634
635 return status;
636}
637
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700638static int arasan_nand_reset(struct mtd_info *mtd,
639 struct arasan_nand_command_format *curr_cmd)
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530640{
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700641 struct nand_chip *chip = mtd_to_nand(mtd);
642 struct nand_drv *info = nand_get_controller_data(chip);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530643 u32 timeout = ARASAN_NAND_POLL_TIMEOUT;
644 u32 cmd_reg = 0;
645
646 writel(ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700647 &info->reg->intsts_enr);
648 cmd_reg = readl(&info->reg->cmd_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530649 cmd_reg &= ~ARASAN_NAND_CMD_CMD12_MASK;
650
651 cmd_reg |= curr_cmd->cmd1 |
652 (curr_cmd->cmd2 << ARASAN_NAND_CMD_CMD2_SHIFT);
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700653 writel(cmd_reg, &info->reg->cmd_reg);
654 writel(curr_cmd->pgm, &info->reg->pgm_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530655
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700656 while (!(readl(&info->reg->intsts_reg) &
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530657 ARASAN_NAND_INT_STS_XFR_CMPLT_MASK) && timeout) {
658 udelay(1);
659 timeout--;
660 }
661 if (!timeout) {
662 printf("ERROR:%s timedout\n", __func__);
663 return -ETIMEDOUT;
664 }
665
666 writel(ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700667 &info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530668
669 writel(ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700670 &info->reg->intsts_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530671
672 return 0;
673}
674
675static u8 arasan_nand_page(struct mtd_info *mtd)
676{
677 u8 page_val = 0;
678
679 switch (mtd->writesize) {
680 case 512:
681 page_val = 0;
682 break;
683 case 2048:
684 page_val = 1;
685 break;
686 case 4096:
687 page_val = 2;
688 break;
689 case 8192:
690 page_val = 3;
691 break;
692 case 16384:
693 page_val = 4;
694 break;
695 case 1024:
696 page_val = 5;
697 break;
698 default:
699 printf("%s:Pagesize>16K\n", __func__);
700 break;
701 }
702
703 return page_val;
704}
705
706static int arasan_nand_send_wrcmd(struct arasan_nand_command_format *curr_cmd,
707 int column, int page_addr, struct mtd_info *mtd)
708{
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700709 struct nand_chip *chip = mtd_to_nand(mtd);
710 struct nand_drv *info = nand_get_controller_data(chip);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530711 u32 reg_val, page;
712 u8 page_val, addr_cycles;
713
714 writel(ARASAN_NAND_INT_STS_BUF_WR_RDY_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700715 &info->reg->intsts_enr);
716 reg_val = readl(&info->reg->cmd_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530717 reg_val &= ~ARASAN_NAND_CMD_CMD12_MASK;
718 reg_val |= curr_cmd->cmd1 |
719 (curr_cmd->cmd2 << ARASAN_NAND_CMD_CMD2_SHIFT);
720 if (curr_cmd->cmd1 == NAND_CMD_SEQIN) {
721 reg_val &= ~ARASAN_NAND_CMD_PG_SIZE_MASK;
722 page_val = arasan_nand_page(mtd);
723 reg_val |= (page_val << ARASAN_NAND_CMD_PG_SIZE_SHIFT);
724 }
725
726 reg_val &= ~ARASAN_NAND_CMD_ADDR_CYCL_MASK;
727 addr_cycles = arasan_nand_get_addrcycle(mtd);
728
729 if (addr_cycles == ARASAN_NAND_INVALID_ADDR_CYCL)
730 return ERR_ADDR_CYCLE;
731
732 reg_val |= (addr_cycles <<
733 ARASAN_NAND_CMD_ADDR_CYCL_SHIFT);
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700734 writel(reg_val, &info->reg->cmd_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530735
736 if (page_addr == -1)
737 page_addr = 0;
738
739 page = (page_addr << ARASAN_NAND_MEM_ADDR1_PAGE_SHIFT) &
740 ARASAN_NAND_MEM_ADDR1_PAGE_MASK;
741 column &= ARASAN_NAND_MEM_ADDR1_COL_MASK;
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700742 writel(page | column, &info->reg->memadr_reg1);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530743
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700744 reg_val = readl(&info->reg->memadr_reg2);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530745 reg_val &= ~ARASAN_NAND_MEM_ADDR2_PAGE_MASK;
746 reg_val |= (page_addr >> ARASAN_NAND_MEM_ADDR1_PAGE_SHIFT);
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700747 writel(reg_val, &info->reg->memadr_reg2);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530748
749 return 0;
750}
751
752static void arasan_nand_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
753{
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700754 struct nand_chip *chip = mtd_to_nand(mtd);
755 struct nand_drv *info = nand_get_controller_data(chip);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530756 u32 reg_val;
757 u32 timeout = ARASAN_NAND_POLL_TIMEOUT;
758
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700759 reg_val = readl(&info->reg->pkt_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530760 reg_val &= ~(ARASAN_NAND_PKT_REG_PKT_CNT_MASK |
761 ARASAN_NAND_PKT_REG_PKT_SIZE_MASK);
762
763 reg_val |= (1 << ARASAN_NAND_PKT_REG_PKT_CNT_SHFT) | len;
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700764 writel(reg_val, &info->reg->pkt_reg);
765 writel(curr_cmd->pgm, &info->reg->pgm_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530766
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700767 while (!(readl(&info->reg->intsts_reg) &
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530768 ARASAN_NAND_INT_STS_BUF_WR_RDY_MASK) && timeout) {
769 udelay(1);
770 timeout--;
771 }
772
773 if (!timeout)
774 puts("ERROR:arasan_nand_write_buf timedout:Buff RDY\n");
775
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700776 reg_val = readl(&info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530777 reg_val |= ARASAN_NAND_INT_STS_XFR_CMPLT_MASK;
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700778 writel(reg_val, &info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530779 writel(reg_val | ARASAN_NAND_INT_STS_BUF_WR_RDY_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700780 &info->reg->intsts_enr);
781 reg_val = readl(&info->reg->intsts_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530782 writel(reg_val | ARASAN_NAND_INT_STS_BUF_WR_RDY_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700783 &info->reg->intsts_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530784
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700785 arasan_nand_fill_tx(mtd, buf, len);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530786
787 timeout = ARASAN_NAND_POLL_TIMEOUT;
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700788 while (!(readl(&info->reg->intsts_reg) &
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530789 ARASAN_NAND_INT_STS_XFR_CMPLT_MASK) && timeout) {
790 udelay(1);
791 timeout--;
792 }
793 if (!timeout)
794 puts("ERROR:arasan_nand_write_buf timedout:Xfer CMPLT\n");
795
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700796 writel(readl(&info->reg->intsts_enr) |
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530797 ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700798 &info->reg->intsts_enr);
799 writel(readl(&info->reg->intsts_reg) |
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530800 ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700801 &info->reg->intsts_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530802}
803
804static int arasan_nand_erase(struct arasan_nand_command_format *curr_cmd,
805 int column, int page_addr, struct mtd_info *mtd)
806{
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700807 struct nand_chip *chip = mtd_to_nand(mtd);
808 struct nand_drv *info = nand_get_controller_data(chip);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530809 u32 reg_val, page;
810 u32 timeout = ARASAN_NAND_POLL_TIMEOUT;
811 u8 row_addr_cycles;
812
813 writel(ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700814 &info->reg->intsts_enr);
815 reg_val = readl(&info->reg->cmd_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530816 reg_val &= ~ARASAN_NAND_CMD_CMD12_MASK;
817 reg_val |= curr_cmd->cmd1 |
818 (curr_cmd->cmd2 << ARASAN_NAND_CMD_CMD2_SHIFT);
819 row_addr_cycles = arasan_nand_get_addrcycle(mtd);
820
821 if (row_addr_cycles == ARASAN_NAND_INVALID_ADDR_CYCL)
822 return ERR_ADDR_CYCLE;
823
824 reg_val &= ~ARASAN_NAND_CMD_ADDR_CYCL_MASK;
825 reg_val |= (row_addr_cycles <<
826 ARASAN_NAND_CMD_ADDR_CYCL_SHIFT);
827
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700828 writel(reg_val, &info->reg->cmd_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530829
Vipul Kumar673a5c22018-03-05 15:24:59 +0530830 page = (page_addr >> ARASAN_NAND_MEM_ADDR1_PAGE_SHIFT) &
Vipul Kumar9d9b99b2018-03-10 17:52:23 +0530831 ARASAN_NAND_MEM_ADDR1_COL_MASK;
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530832 column = page_addr & ARASAN_NAND_MEM_ADDR1_COL_MASK;
Vipul Kumar673a5c22018-03-05 15:24:59 +0530833 writel(column | (page << ARASAN_NAND_MEM_ADDR1_PAGE_SHIFT),
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700834 &info->reg->memadr_reg1);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530835
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700836 reg_val = readl(&info->reg->memadr_reg2);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530837 reg_val &= ~ARASAN_NAND_MEM_ADDR2_PAGE_MASK;
838 reg_val |= (page_addr >> ARASAN_NAND_MEM_ADDR1_PAGE_SHIFT);
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700839 writel(reg_val, &info->reg->memadr_reg2);
840 writel(curr_cmd->pgm, &info->reg->pgm_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530841
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700842 while (!(readl(&info->reg->intsts_reg) &
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530843 ARASAN_NAND_INT_STS_XFR_CMPLT_MASK) && timeout) {
844 udelay(1);
845 timeout--;
846 }
847 if (!timeout) {
848 printf("ERROR:%s timedout:Xfer CMPLT\n", __func__);
849 return -ETIMEDOUT;
850 }
851
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700852 reg_val = readl(&info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530853 writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700854 &info->reg->intsts_enr);
855 reg_val = readl(&info->reg->intsts_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530856 writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700857 &info->reg->intsts_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530858
859 return 0;
860}
861
862static int arasan_nand_read_status(struct arasan_nand_command_format *curr_cmd,
863 int column, int page_addr, struct mtd_info *mtd)
864{
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700865 struct nand_chip *chip = mtd_to_nand(mtd);
866 struct nand_drv *info = nand_get_controller_data(chip);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530867 u32 reg_val;
868 u32 timeout = ARASAN_NAND_POLL_TIMEOUT;
869 u8 addr_cycles;
870
871 writel(ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700872 &info->reg->intsts_enr);
873 reg_val = readl(&info->reg->cmd_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530874 reg_val &= ~ARASAN_NAND_CMD_CMD12_MASK;
875 reg_val |= curr_cmd->cmd1 |
876 (curr_cmd->cmd2 << ARASAN_NAND_CMD_CMD2_SHIFT);
877 addr_cycles = arasan_nand_get_addrcycle(mtd);
878
879 if (addr_cycles == ARASAN_NAND_INVALID_ADDR_CYCL)
880 return ERR_ADDR_CYCLE;
881
882 reg_val &= ~ARASAN_NAND_CMD_ADDR_CYCL_MASK;
883 reg_val |= (addr_cycles <<
884 ARASAN_NAND_CMD_ADDR_CYCL_SHIFT);
885
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700886 writel(reg_val, &info->reg->cmd_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530887
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700888 reg_val = readl(&info->reg->pkt_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530889 reg_val &= ~(ARASAN_NAND_PKT_REG_PKT_CNT_MASK |
890 ARASAN_NAND_PKT_REG_PKT_SIZE_MASK);
891 reg_val |= (1 << ARASAN_NAND_PKT_REG_PKT_CNT_SHFT) | 1;
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700892 writel(reg_val, &info->reg->pkt_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530893
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700894 writel(curr_cmd->pgm, &info->reg->pgm_reg);
895 while (!(readl(&info->reg->intsts_reg) &
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530896 ARASAN_NAND_INT_STS_XFR_CMPLT_MASK) && timeout) {
897 udelay(1);
898 timeout--;
899 }
900
901 if (!timeout) {
902 printf("ERROR:%s: timedout:Xfer CMPLT\n", __func__);
903 return -ETIMEDOUT;
904 }
905
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700906 reg_val = readl(&info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530907 writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700908 &info->reg->intsts_enr);
909 reg_val = readl(&info->reg->intsts_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530910 writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700911 &info->reg->intsts_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530912
913 return 0;
914}
915
916static int arasan_nand_send_rdcmd(struct arasan_nand_command_format *curr_cmd,
917 int column, int page_addr, struct mtd_info *mtd)
918{
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700919 struct nand_chip *chip = mtd_to_nand(mtd);
920 struct nand_drv *info = nand_get_controller_data(chip);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530921 u32 reg_val, addr_cycles, page;
922 u8 page_val;
923
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700924 reg_val = readl(&info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530925 writel(reg_val | ARASAN_NAND_INT_STS_BUF_RD_RDY_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700926 &info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530927
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700928 reg_val = readl(&info->reg->cmd_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530929 reg_val &= ~ARASAN_NAND_CMD_CMD12_MASK;
930 reg_val |= curr_cmd->cmd1 |
931 (curr_cmd->cmd2 << ARASAN_NAND_CMD_CMD2_SHIFT);
932
933 if (curr_cmd->cmd1 == NAND_CMD_RNDOUT ||
934 curr_cmd->cmd1 == NAND_CMD_READ0) {
935 reg_val &= ~ARASAN_NAND_CMD_PG_SIZE_MASK;
936 page_val = arasan_nand_page(mtd);
937 reg_val |= (page_val << ARASAN_NAND_CMD_PG_SIZE_SHIFT);
938 }
939
Siva Durga Prasad Paladugu99459c22016-08-25 16:00:04 +0530940 reg_val &= ~ARASAN_NAND_CMD_ECC_ON_MASK;
941
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530942 reg_val &= ~ARASAN_NAND_CMD_ADDR_CYCL_MASK;
943
944 addr_cycles = arasan_nand_get_addrcycle(mtd);
945
946 if (addr_cycles == ARASAN_NAND_INVALID_ADDR_CYCL)
947 return ERR_ADDR_CYCLE;
948
949 reg_val |= (addr_cycles << 28);
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700950 writel(reg_val, &info->reg->cmd_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530951
952 if (page_addr == -1)
953 page_addr = 0;
954
955 page = (page_addr << ARASAN_NAND_MEM_ADDR1_PAGE_SHIFT) &
956 ARASAN_NAND_MEM_ADDR1_PAGE_MASK;
957 column &= ARASAN_NAND_MEM_ADDR1_COL_MASK;
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700958 writel(page | column, &info->reg->memadr_reg1);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530959
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700960 reg_val = readl(&info->reg->memadr_reg2);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530961 reg_val &= ~ARASAN_NAND_MEM_ADDR2_PAGE_MASK;
962 reg_val |= (page_addr >> ARASAN_NAND_MEM_ADDR1_PAGE_SHIFT);
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700963 writel(reg_val, &info->reg->memadr_reg2);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530964
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530965 buf_index = 0;
966
967 return 0;
968}
969
970static void arasan_nand_read_buf(struct mtd_info *mtd, u8 *buf, int size)
971{
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700972 struct nand_chip *chip = mtd_to_nand(mtd);
973 struct nand_drv *info = nand_get_controller_data(chip);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530974 u32 reg_val, i;
975 u32 *bufptr = (u32 *)buf;
976 u32 timeout = ARASAN_NAND_POLL_TIMEOUT;
977
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700978 reg_val = readl(&info->reg->pkt_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530979 reg_val &= ~(ARASAN_NAND_PKT_REG_PKT_CNT_MASK |
980 ARASAN_NAND_PKT_REG_PKT_SIZE_MASK);
981 reg_val |= (1 << ARASAN_NAND_PKT_REG_PKT_CNT_SHFT) | size;
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700982 writel(reg_val, &info->reg->pkt_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530983
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700984 writel(curr_cmd->pgm, &info->reg->pgm_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530985
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700986 while (!(readl(&info->reg->intsts_reg) &
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530987 ARASAN_NAND_INT_STS_BUF_RD_RDY_MASK) && timeout) {
988 udelay(1);
989 timeout--;
990 }
991
992 if (!timeout)
993 puts("ERROR:arasan_nand_read_buf timedout:Buff RDY\n");
994
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700995 reg_val = readl(&info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530996 reg_val |= ARASAN_NAND_INT_STS_XFR_CMPLT_MASK;
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700997 writel(reg_val, &info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530998
999 writel(reg_val | ARASAN_NAND_INT_STS_BUF_RD_RDY_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -07001000 &info->reg->intsts_enr);
1001 reg_val = readl(&info->reg->intsts_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301002 writel(reg_val | ARASAN_NAND_INT_STS_BUF_RD_RDY_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -07001003 &info->reg->intsts_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301004
1005 buf_index = 0;
1006 for (i = 0; i < size / 4; i++)
Ashok Reddy Soma13e92302019-12-19 02:27:43 -07001007 bufptr[i] = readl(&info->reg->buf_dataport);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301008
1009 if (size & 0x03)
Ashok Reddy Soma13e92302019-12-19 02:27:43 -07001010 bufptr[i] = readl(&info->reg->buf_dataport);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301011
1012 timeout = ARASAN_NAND_POLL_TIMEOUT;
1013
Ashok Reddy Soma13e92302019-12-19 02:27:43 -07001014 while (!(readl(&info->reg->intsts_reg) &
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301015 ARASAN_NAND_INT_STS_XFR_CMPLT_MASK) && timeout) {
1016 udelay(1);
1017 timeout--;
1018 }
1019
1020 if (!timeout)
1021 puts("ERROR:arasan_nand_read_buf timedout:Xfer CMPLT\n");
1022
Ashok Reddy Soma13e92302019-12-19 02:27:43 -07001023 reg_val = readl(&info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301024 writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -07001025 &info->reg->intsts_enr);
1026 reg_val = readl(&info->reg->intsts_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301027 writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -07001028 &info->reg->intsts_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301029}
1030
1031static u8 arasan_nand_read_byte(struct mtd_info *mtd)
1032{
Scott Wood17fed142016-05-30 13:57:56 -05001033 struct nand_chip *chip = mtd_to_nand(mtd);
Ashok Reddy Soma13e92302019-12-19 02:27:43 -07001034 struct nand_drv *info = nand_get_controller_data(chip);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301035 u32 size;
1036 u8 val;
1037 struct nand_onfi_params *p;
1038
1039 if (buf_index == 0) {
1040 p = &chip->onfi_params;
1041 if (curr_cmd->cmd1 == NAND_CMD_READID)
1042 size = 4;
1043 else if (curr_cmd->cmd1 == NAND_CMD_PARAM)
1044 size = sizeof(struct nand_onfi_params);
1045 else if (curr_cmd->cmd1 == NAND_CMD_RNDOUT)
1046 size = le16_to_cpu(p->ext_param_page_length) * 16;
1047 else if (curr_cmd->cmd1 == NAND_CMD_GET_FEATURES)
1048 size = 4;
1049 else if (curr_cmd->cmd1 == NAND_CMD_STATUS)
Ashok Reddy Soma13e92302019-12-19 02:27:43 -07001050 return readb(&info->reg->flash_sts_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301051 else
1052 size = 8;
1053 chip->read_buf(mtd, &buf_data[0], size);
1054 }
1055
1056 val = *(&buf_data[0] + buf_index);
1057 buf_index++;
1058
1059 return val;
1060}
1061
1062static void arasan_nand_cmd_function(struct mtd_info *mtd, unsigned int command,
1063 int column, int page_addr)
1064{
Scott Wood17fed142016-05-30 13:57:56 -05001065 struct nand_chip *chip = mtd_to_nand(mtd);
Ashok Reddy Soma13e92302019-12-19 02:27:43 -07001066 struct nand_drv *info = nand_get_controller_data(chip);
1067 struct nand_config *nand = &info->config;
1068 u32 i, ret = 0;
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301069
1070 curr_cmd = NULL;
1071 writel(ARASAN_NAND_INT_STS_XFR_CMPLT_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -07001072 &info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301073
1074 if ((command == NAND_CMD_READOOB) &&
1075 (mtd->writesize > 512)) {
1076 column += mtd->writesize;
1077 command = NAND_CMD_READ0;
1078 }
1079
1080 /* Get the command format */
1081 for (i = 0; (arasan_nand_commands[i].cmd1 != NAND_CMD_NONE ||
1082 arasan_nand_commands[i].cmd2 != NAND_CMD_NONE); i++) {
1083 if (command == arasan_nand_commands[i].cmd1) {
1084 curr_cmd = &arasan_nand_commands[i];
1085 break;
1086 }
1087 }
1088
1089 if (curr_cmd == NULL) {
1090 printf("Unsupported Command; 0x%x\n", command);
1091 return;
1092 }
1093
1094 if (curr_cmd->cmd1 == NAND_CMD_RESET)
Ashok Reddy Soma13e92302019-12-19 02:27:43 -07001095 ret = arasan_nand_reset(mtd, curr_cmd);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301096
1097 if ((curr_cmd->cmd1 == NAND_CMD_READID) ||
1098 (curr_cmd->cmd1 == NAND_CMD_PARAM) ||
1099 (curr_cmd->cmd1 == NAND_CMD_RNDOUT) ||
1100 (curr_cmd->cmd1 == NAND_CMD_GET_FEATURES) ||
1101 (curr_cmd->cmd1 == NAND_CMD_READ0))
1102 ret = arasan_nand_send_rdcmd(curr_cmd, column, page_addr, mtd);
1103
1104 if ((curr_cmd->cmd1 == NAND_CMD_SET_FEATURES) ||
1105 (curr_cmd->cmd1 == NAND_CMD_SEQIN)) {
1106 nand->page = page_addr;
1107 ret = arasan_nand_send_wrcmd(curr_cmd, column, page_addr, mtd);
1108 }
1109
1110 if (curr_cmd->cmd1 == NAND_CMD_ERASE1)
1111 ret = arasan_nand_erase(curr_cmd, column, page_addr, mtd);
1112
1113 if (curr_cmd->cmd1 == NAND_CMD_STATUS)
1114 ret = arasan_nand_read_status(curr_cmd, column, page_addr, mtd);
1115
1116 if (ret != 0)
1117 printf("ERROR:%s:command:0x%x\n", __func__, curr_cmd->cmd1);
1118}
1119
Siva Durga Prasad Paladugu45e512c2018-01-04 16:04:21 +05301120static void arasan_check_ondie(struct mtd_info *mtd)
1121{
1122 struct nand_chip *nand_chip = mtd_to_nand(mtd);
T Karthik Reddy4de4f382020-01-19 23:59:23 -07001123 struct nand_drv *info = nand_get_controller_data(nand_chip);
1124 struct nand_config *nand = &info->config;
Siva Durga Prasad Paladugu45e512c2018-01-04 16:04:21 +05301125 u8 maf_id, dev_id;
1126 u8 get_feature[4];
1127 u8 set_feature[4] = {ENABLE_ONDIE_ECC, 0x00, 0x00, 0x00};
1128 u32 i;
1129
T Karthik Reddy4de4f382020-01-19 23:59:23 -07001130 nand_chip->select_chip(mtd, 0);
1131
Siva Durga Prasad Paladugu45e512c2018-01-04 16:04:21 +05301132 /* Send the command for reading device ID */
1133 nand_chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
1134 nand_chip->cmdfunc(mtd, NAND_CMD_READID, 0, -1);
1135
1136 /* Read manufacturer and device IDs */
1137 maf_id = nand_chip->read_byte(mtd);
1138 dev_id = nand_chip->read_byte(mtd);
1139
1140 if ((maf_id == NAND_MFR_MICRON) &&
1141 ((dev_id == 0xf1) || (dev_id == 0xa1) || (dev_id == 0xb1) ||
1142 (dev_id == 0xaa) || (dev_id == 0xba) || (dev_id == 0xda) ||
1143 (dev_id == 0xca) || (dev_id == 0xac) || (dev_id == 0xbc) ||
1144 (dev_id == 0xdc) || (dev_id == 0xcc) || (dev_id == 0xa3) ||
1145 (dev_id == 0xb3) || (dev_id == 0xd3) || (dev_id == 0xc3))) {
1146 nand_chip->cmdfunc(mtd, NAND_CMD_SET_FEATURES,
1147 ONDIE_ECC_FEATURE_ADDR, -1);
1148
1149 nand_chip->write_buf(mtd, &set_feature[0], 4);
1150 nand_chip->cmdfunc(mtd, NAND_CMD_GET_FEATURES,
1151 ONDIE_ECC_FEATURE_ADDR, -1);
1152
1153 for (i = 0; i < 4; i++)
1154 get_feature[i] = nand_chip->read_byte(mtd);
1155
T Karthik Reddy4de4f382020-01-19 23:59:23 -07001156 if (get_feature[0] & ENABLE_ONDIE_ECC) {
Siva Durga Prasad Paladugu45e512c2018-01-04 16:04:21 +05301157 nand->on_die_ecc_enabled = true;
T Karthik Reddy4de4f382020-01-19 23:59:23 -07001158 printf("On-DIE ECC Enabled\n");
1159 } else {
Siva Durga Prasad Paladugu45e512c2018-01-04 16:04:21 +05301160 printf("%s: Unable to enable OnDie ECC\n", __func__);
T Karthik Reddy4de4f382020-01-19 23:59:23 -07001161 }
Siva Durga Prasad Paladugu45e512c2018-01-04 16:04:21 +05301162
1163 /* Use the BBT pattern descriptors */
1164 nand_chip->bbt_td = &bbt_main_descr;
1165 nand_chip->bbt_md = &bbt_mirror_descr;
1166 }
1167}
1168
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301169static int arasan_nand_ecc_init(struct mtd_info *mtd)
1170{
Ashok Reddy Soma13e92302019-12-19 02:27:43 -07001171 struct nand_chip *nand_chip = mtd_to_nand(mtd);
1172 struct nand_drv *info = nand_get_controller_data(nand_chip);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301173 int found = -1;
Siva Durga Prasad Paladugub0a4f132018-01-04 16:04:22 +05301174 u32 regval, eccpos_start, i, eccaddr;
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301175
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301176 for (i = 0; i < ARRAY_SIZE(ecc_matrix); i++) {
1177 if ((ecc_matrix[i].pagesize == mtd->writesize) &&
1178 (ecc_matrix[i].ecc_codeword_size >=
1179 nand_chip->ecc_step_ds)) {
1180 if (ecc_matrix[i].eccbits >=
1181 nand_chip->ecc_strength_ds) {
1182 found = i;
1183 break;
1184 }
1185 found = i;
1186 }
1187 }
1188
1189 if (found < 0)
1190 return 1;
1191
Siva Durga Prasad Paladugub0a4f132018-01-04 16:04:22 +05301192 eccaddr = mtd->writesize + mtd->oobsize -
1193 ecc_matrix[found].eccsize;
1194
1195 regval = eccaddr |
Siva Durga Prasad Paladugudb796632016-05-25 15:20:38 +05301196 (ecc_matrix[found].eccsize << ARASAN_NAND_ECC_SIZE_SHIFT) |
1197 (ecc_matrix[found].bch << ARASAN_NAND_ECC_BCH_SHIFT);
Ashok Reddy Soma13e92302019-12-19 02:27:43 -07001198 writel(regval, &info->reg->ecc_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301199
Siva Durga Prasad Paladugudb796632016-05-25 15:20:38 +05301200 if (ecc_matrix[found].bch) {
Ashok Reddy Soma13e92302019-12-19 02:27:43 -07001201 regval = readl(&info->reg->memadr_reg2);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301202 regval &= ~ARASAN_NAND_MEM_ADDR2_BCH_MASK;
Siva Durga Prasad Paladugudb796632016-05-25 15:20:38 +05301203 regval |= (ecc_matrix[found].bchval <<
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301204 ARASAN_NAND_MEM_ADDR2_BCH_SHIFT);
Ashok Reddy Soma13e92302019-12-19 02:27:43 -07001205 writel(regval, &info->reg->memadr_reg2);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301206 }
1207
Siva Durga Prasad Paladugudb796632016-05-25 15:20:38 +05301208 nand_oob.eccbytes = ecc_matrix[found].eccsize;
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301209 eccpos_start = mtd->oobsize - nand_oob.eccbytes;
1210
1211 for (i = 0; i < nand_oob.eccbytes; i++)
1212 nand_oob.eccpos[i] = eccpos_start + i;
1213
1214 nand_oob.oobfree[0].offset = 2;
1215 nand_oob.oobfree[0].length = eccpos_start - 2;
1216
Siva Durga Prasad Paladugudb796632016-05-25 15:20:38 +05301217 nand_chip->ecc.size = ecc_matrix[found].ecc_codeword_size;
1218 nand_chip->ecc.strength = ecc_matrix[found].eccbits;
1219 nand_chip->ecc.bytes = ecc_matrix[found].eccsize;
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301220 nand_chip->ecc.layout = &nand_oob;
1221
1222 return 0;
1223}
1224
Ashok Reddy Somac7b66332019-12-19 02:27:42 -07001225static int arasan_probe(struct udevice *dev)
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301226{
Ashok Reddy Somac7b66332019-12-19 02:27:42 -07001227 struct arasan_nand_info *arasan = dev_get_priv(dev);
1228 struct nand_chip *nand_chip = &arasan->nand_chip;
Ashok Reddy Soma13e92302019-12-19 02:27:43 -07001229 struct nand_drv *info = &arasan->nand_ctrl;
1230 struct nand_config *nand = &info->config;
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301231 struct mtd_info *mtd;
Ashok Reddy Somaaf1d3cf2023-02-23 22:07:07 -07001232 ofnode child;
Venkatesh Yadav Abbarapu7a1d17a2024-03-06 09:04:04 +05301233 int ret;
Venkatesh Yadav Abbarapu263fa962024-03-06 08:57:03 +05301234 const char *str;
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301235
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 */
Venkatesh Yadav Abbarapu7a1d17a2024-03-06 09:04:04 +05301260 ret = nand_scan_ident(mtd, CONFIG_SYS_NAND_MAX_CHIPS, NULL);
1261 if (ret) {
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301262 printf("%s: nand_scan_ident failed\n", __func__);
Venkatesh Yadav Abbarapu7a1d17a2024-03-06 09:04:04 +05301263 return ret;
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301264 }
1265
Venkatesh Yadav Abbarapu263fa962024-03-06 08:57:03 +05301266 str = ofnode_read_string(nand_chip->flash_node, "nand-ecc-mode");
1267 if (!str || strcmp(str, "hw") != 0) {
1268 printf("%s ecc mode is not supported\n", str);
1269 return -EINVAL;
1270 }
1271
Siva Durga Prasad Paladugu80c889c2018-01-04 16:04:20 +05301272 nand_chip->ecc.mode = NAND_ECC_HW;
1273 nand_chip->ecc.hwctl = NULL;
1274 nand_chip->ecc.read_page = arasan_nand_read_page_hwecc;
1275 nand_chip->ecc.write_page = arasan_nand_write_page_hwecc;
1276 nand_chip->ecc.read_oob = arasan_nand_read_oob;
1277 nand_chip->ecc.write_oob = arasan_nand_write_oob;
1278
Siva Durga Prasad Paladugu45e512c2018-01-04 16:04:21 +05301279 arasan_check_ondie(mtd);
1280
1281 /*
1282 * If on die supported, then give priority to on-die ecc and use
1283 * it instead of controller ecc.
1284 */
1285 if (nand->on_die_ecc_enabled) {
1286 nand_chip->ecc.strength = 1;
1287 nand_chip->ecc.size = mtd->writesize;
1288 nand_chip->ecc.bytes = 0;
1289 nand_chip->ecc.layout = &ondie_nand_oob_64;
1290 } else {
Venkatesh Yadav Abbarapu7a1d17a2024-03-06 09:04:04 +05301291 ret = arasan_nand_ecc_init(mtd);
1292 if (ret) {
Siva Durga Prasad Paladugu45e512c2018-01-04 16:04:21 +05301293 printf("%s: nand_ecc_init failed\n", __func__);
Venkatesh Yadav Abbarapu7a1d17a2024-03-06 09:04:04 +05301294 return ret;
Siva Durga Prasad Paladugu45e512c2018-01-04 16:04:21 +05301295 }
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301296 }
1297
Venkatesh Yadav Abbarapu7a1d17a2024-03-06 09:04:04 +05301298 ret = nand_scan_tail(mtd);
1299 if (ret) {
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301300 printf("%s: nand_scan_tail failed\n", __func__);
Venkatesh Yadav Abbarapu7a1d17a2024-03-06 09:04:04 +05301301 return ret;
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301302 }
1303
Venkatesh Yadav Abbarapu7a1d17a2024-03-06 09:04:04 +05301304 ret = nand_register(0, mtd);
1305 if (ret) {
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301306 printf("Nand Register Fail\n");
Venkatesh Yadav Abbarapu7a1d17a2024-03-06 09:04:04 +05301307 return ret;
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301308 }
1309
Venkatesh Yadav Abbarapu7a1d17a2024-03-06 09:04:04 +05301310 return ret;
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301311}
1312
Ashok Reddy Somac7b66332019-12-19 02:27:42 -07001313static const struct udevice_id arasan_nand_dt_ids[] = {
1314 {.compatible = "arasan,nfc-v3p10",},
1315 { /* sentinel */ }
1316};
1317
1318U_BOOT_DRIVER(arasan_nand) = {
Michal Simek33093082020-01-07 08:50:34 +01001319 .name = "arasan_nand",
Ashok Reddy Somac7b66332019-12-19 02:27:42 -07001320 .id = UCLASS_MTD,
1321 .of_match = arasan_nand_dt_ids,
1322 .probe = arasan_probe,
Simon Glass8a2b47f2020-12-03 16:55:17 -07001323 .priv_auto = sizeof(struct arasan_nand_info),
Ashok Reddy Somac7b66332019-12-19 02:27:42 -07001324};
1325
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301326void board_nand_init(void)
1327{
Ashok Reddy Somac7b66332019-12-19 02:27:42 -07001328 struct udevice *dev;
1329 int ret;
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301330
Ashok Reddy Somac7b66332019-12-19 02:27:42 -07001331 ret = uclass_get_device_by_driver(UCLASS_MTD,
Simon Glass65130cd2020-12-28 20:34:56 -07001332 DM_DRIVER_GET(arasan_nand), &dev);
Ashok Reddy Somac7b66332019-12-19 02:27:42 -07001333 if (ret && ret != -ENODEV)
1334 pr_err("Failed to initialize %s. (error %d)\n", dev->name, ret);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301335}