blob: d1b1a4263a2e3fe8b3ce4c7849de65df00d790df [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>
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>
20
Ashok Reddy Somac7b66332019-12-19 02:27:42 -070021struct nand_config {
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +053022 u32 page;
Siva Durga Prasad Paladugu45e512c2018-01-04 16:04:21 +053023 bool on_die_ecc_enabled;
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +053024};
25
Ashok Reddy Soma13e92302019-12-19 02:27:43 -070026struct nand_drv {
27 struct nand_regs *reg;
28 struct nand_config config;
29};
30
Ashok Reddy Somac7b66332019-12-19 02:27:42 -070031struct arasan_nand_info {
32 struct udevice *dev;
Ashok Reddy Soma13e92302019-12-19 02:27:43 -070033 struct nand_drv nand_ctrl;
Ashok Reddy Somac7b66332019-12-19 02:27:42 -070034 struct nand_chip nand_chip;
35};
36
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +053037struct nand_regs {
38 u32 pkt_reg;
39 u32 memadr_reg1;
40 u32 memadr_reg2;
41 u32 cmd_reg;
42 u32 pgm_reg;
43 u32 intsts_enr;
44 u32 intsig_enr;
45 u32 intsts_reg;
46 u32 rdy_busy;
47 u32 cms_sysadr_reg;
48 u32 flash_sts_reg;
49 u32 tmg_reg;
50 u32 buf_dataport;
51 u32 ecc_reg;
52 u32 ecc_errcnt_reg;
53 u32 ecc_sprcmd_reg;
54 u32 errcnt_1bitreg;
55 u32 errcnt_2bitreg;
56 u32 errcnt_3bitreg;
57 u32 errcnt_4bitreg;
58 u32 dma_sysadr0_reg;
59 u32 dma_bufbdry_reg;
60 u32 cpu_rls_reg;
61 u32 errcnt_5bitreg;
62 u32 errcnt_6bitreg;
63 u32 errcnt_7bitreg;
64 u32 errcnt_8bitreg;
65 u32 data_if_reg;
66};
67
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +053068struct arasan_nand_command_format {
69 u8 cmd1;
70 u8 cmd2;
71 u8 addr_cycles;
72 u32 pgm;
73};
74
75#define ONDIE_ECC_FEATURE_ADDR 0x90
Siva Durga Prasad Paladugu45e512c2018-01-04 16:04:21 +053076#define ENABLE_ONDIE_ECC 0x08
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +053077
78#define ARASAN_PROG_RD_MASK 0x00000001
79#define ARASAN_PROG_BLK_ERS_MASK 0x00000004
80#define ARASAN_PROG_RD_ID_MASK 0x00000040
81#define ARASAN_PROG_RD_STS_MASK 0x00000008
82#define ARASAN_PROG_PG_PROG_MASK 0x00000010
83#define ARASAN_PROG_RD_PARAM_PG_MASK 0x00000080
84#define ARASAN_PROG_RST_MASK 0x00000100
85#define ARASAN_PROG_GET_FTRS_MASK 0x00000200
86#define ARASAN_PROG_SET_FTRS_MASK 0x00000400
87#define ARASAN_PROG_CHNG_ROWADR_END_MASK 0x00400000
88
89#define ARASAN_NAND_CMD_ECC_ON_MASK 0x80000000
90#define ARASAN_NAND_CMD_CMD12_MASK 0xFFFF
91#define ARASAN_NAND_CMD_PG_SIZE_MASK 0x3800000
92#define ARASAN_NAND_CMD_PG_SIZE_SHIFT 23
93#define ARASAN_NAND_CMD_CMD2_SHIFT 8
94#define ARASAN_NAND_CMD_ADDR_CYCL_MASK 0x70000000
95#define ARASAN_NAND_CMD_ADDR_CYCL_SHIFT 28
96
Vipul Kumar9d9b99b2018-03-10 17:52:23 +053097#define ARASAN_NAND_MEM_ADDR1_PAGE_MASK 0xFFFF0000
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +053098#define ARASAN_NAND_MEM_ADDR1_COL_MASK 0xFFFF
99#define ARASAN_NAND_MEM_ADDR1_PAGE_SHIFT 16
100#define ARASAN_NAND_MEM_ADDR2_PAGE_MASK 0xFF
101#define ARASAN_NAND_MEM_ADDR2_CS_MASK 0xC0000000
T Karthik Reddy7cd85222018-12-03 16:11:58 +0530102#define ARASAN_NAND_MEM_ADDR2_CS0_MASK (0x3 << 30)
103#define ARASAN_NAND_MEM_ADDR2_CS1_MASK (0x1 << 30)
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530104#define ARASAN_NAND_MEM_ADDR2_BCH_MASK 0xE000000
105#define ARASAN_NAND_MEM_ADDR2_BCH_SHIFT 25
106
107#define ARASAN_NAND_INT_STS_ERR_EN_MASK 0x10
108#define ARASAN_NAND_INT_STS_MUL_BIT_ERR_MASK 0x08
109#define ARASAN_NAND_INT_STS_BUF_RD_RDY_MASK 0x02
110#define ARASAN_NAND_INT_STS_BUF_WR_RDY_MASK 0x01
111#define ARASAN_NAND_INT_STS_XFR_CMPLT_MASK 0x04
112
113#define ARASAN_NAND_PKT_REG_PKT_CNT_MASK 0xFFF000
114#define ARASAN_NAND_PKT_REG_PKT_SIZE_MASK 0x7FF
115#define ARASAN_NAND_PKT_REG_PKT_CNT_SHFT 12
116
117#define ARASAN_NAND_ROW_ADDR_CYCL_MASK 0x0F
118#define ARASAN_NAND_COL_ADDR_CYCL_MASK 0xF0
119#define ARASAN_NAND_COL_ADDR_CYCL_SHIFT 4
120
121#define ARASAN_NAND_ECC_SIZE_SHIFT 16
122#define ARASAN_NAND_ECC_BCH_SHIFT 27
123
124#define ARASAN_NAND_PKTSIZE_1K 1024
125#define ARASAN_NAND_PKTSIZE_512 512
126
127#define ARASAN_NAND_POLL_TIMEOUT 1000000
128#define ARASAN_NAND_INVALID_ADDR_CYCL 0xFF
129
130#define ERR_ADDR_CYCLE -1
131#define READ_BUFF_SIZE 0x4000
132
133static struct arasan_nand_command_format *curr_cmd;
134
135enum addr_cycles {
136 NAND_ADDR_CYCL_NONE,
137 NAND_ADDR_CYCL_ONE,
138 NAND_ADDR_CYCL_ROW,
139 NAND_ADDR_CYCL_COL,
140 NAND_ADDR_CYCL_BOTH,
141};
142
143static struct arasan_nand_command_format arasan_nand_commands[] = {
144 {NAND_CMD_READ0, NAND_CMD_READSTART, NAND_ADDR_CYCL_BOTH,
145 ARASAN_PROG_RD_MASK},
146 {NAND_CMD_RNDOUT, NAND_CMD_RNDOUTSTART, NAND_ADDR_CYCL_COL,
147 ARASAN_PROG_RD_MASK},
148 {NAND_CMD_READID, NAND_CMD_NONE, NAND_ADDR_CYCL_ONE,
149 ARASAN_PROG_RD_ID_MASK},
150 {NAND_CMD_STATUS, NAND_CMD_NONE, NAND_ADDR_CYCL_NONE,
151 ARASAN_PROG_RD_STS_MASK},
152 {NAND_CMD_SEQIN, NAND_CMD_PAGEPROG, NAND_ADDR_CYCL_BOTH,
153 ARASAN_PROG_PG_PROG_MASK},
154 {NAND_CMD_RNDIN, NAND_CMD_NONE, NAND_ADDR_CYCL_COL,
155 ARASAN_PROG_CHNG_ROWADR_END_MASK},
156 {NAND_CMD_ERASE1, NAND_CMD_ERASE2, NAND_ADDR_CYCL_ROW,
157 ARASAN_PROG_BLK_ERS_MASK},
158 {NAND_CMD_RESET, NAND_CMD_NONE, NAND_ADDR_CYCL_NONE,
159 ARASAN_PROG_RST_MASK},
160 {NAND_CMD_PARAM, NAND_CMD_NONE, NAND_ADDR_CYCL_ONE,
161 ARASAN_PROG_RD_PARAM_PG_MASK},
162 {NAND_CMD_GET_FEATURES, NAND_CMD_NONE, NAND_ADDR_CYCL_ONE,
163 ARASAN_PROG_GET_FTRS_MASK},
164 {NAND_CMD_SET_FEATURES, NAND_CMD_NONE, NAND_ADDR_CYCL_ONE,
165 ARASAN_PROG_SET_FTRS_MASK},
166 {NAND_CMD_NONE, NAND_CMD_NONE, NAND_ADDR_CYCL_NONE, 0},
167};
168
169struct arasan_ecc_matrix {
170 u32 pagesize;
171 u32 ecc_codeword_size;
172 u8 eccbits;
173 u8 bch;
174 u8 bchval;
175 u16 eccaddr;
176 u16 eccsize;
177};
178
179static const struct arasan_ecc_matrix ecc_matrix[] = {
180 {512, 512, 1, 0, 0, 0x20D, 0x3},
181 {512, 512, 4, 1, 3, 0x209, 0x7},
182 {512, 512, 8, 1, 2, 0x203, 0xD},
183 /*
184 * 2K byte page
185 */
186 {2048, 512, 1, 0, 0, 0x834, 0xC},
187 {2048, 512, 4, 1, 3, 0x826, 0x1A},
188 {2048, 512, 8, 1, 2, 0x80c, 0x34},
189 {2048, 512, 12, 1, 1, 0x822, 0x4E},
190 {2048, 512, 16, 1, 0, 0x808, 0x68},
191 {2048, 1024, 24, 1, 4, 0x81c, 0x54},
192 /*
193 * 4K byte page
194 */
195 {4096, 512, 1, 0, 0, 0x1068, 0x18},
196 {4096, 512, 4, 1, 3, 0x104c, 0x34},
197 {4096, 512, 8, 1, 2, 0x1018, 0x68},
198 {4096, 512, 12, 1, 1, 0x1044, 0x9C},
199 {4096, 512, 16, 1, 0, 0x1010, 0xD0},
200 {4096, 1024, 24, 1, 4, 0x1038, 0xA8},
201 /*
202 * 8K byte page
203 */
204 {8192, 512, 1, 0, 0, 0x20d0, 0x30},
205 {8192, 512, 4, 1, 3, 0x2098, 0x68},
206 {8192, 512, 8, 1, 2, 0x2030, 0xD0},
207 {8192, 512, 12, 1, 1, 0x2088, 0x138},
208 {8192, 512, 16, 1, 0, 0x2020, 0x1A0},
209 {8192, 1024, 24, 1, 4, 0x2070, 0x150},
210 /*
211 * 16K byte page
212 */
213 {16384, 512, 1, 0, 0, 0x4460, 0x60},
214 {16384, 512, 4, 1, 3, 0x43f0, 0xD0},
215 {16384, 512, 8, 1, 2, 0x4320, 0x1A0},
216 {16384, 512, 12, 1, 1, 0x4250, 0x270},
217 {16384, 512, 16, 1, 0, 0x4180, 0x340},
218 {16384, 1024, 24, 1, 4, 0x4220, 0x2A0}
219};
220
Siva Durga Prasad Paladugu45e512c2018-01-04 16:04:21 +0530221static struct nand_ecclayout ondie_nand_oob_64 = {
222 .eccbytes = 32,
223
224 .eccpos = {
225 8, 9, 10, 11, 12, 13, 14, 15,
226 24, 25, 26, 27, 28, 29, 30, 31,
227 40, 41, 42, 43, 44, 45, 46, 47,
228 56, 57, 58, 59, 60, 61, 62, 63
229 },
230
231 .oobfree = {
232 { .offset = 4, .length = 4 },
233 { .offset = 20, .length = 4 },
234 { .offset = 36, .length = 4 },
235 { .offset = 52, .length = 4 }
236 }
237};
238
239/*
240 * bbt decriptors for chips with on-die ECC and
241 * chips with 64-byte OOB
242 */
243static u8 bbt_pattern[] = {'B', 'b', 't', '0' };
244static u8 mirror_pattern[] = {'1', 't', 'b', 'B' };
245
246static struct nand_bbt_descr bbt_main_descr = {
247 .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE |
248 NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
249 .offs = 4,
250 .len = 4,
251 .veroffs = 20,
252 .maxblocks = 4,
253 .pattern = bbt_pattern
254};
255
256static struct nand_bbt_descr bbt_mirror_descr = {
257 .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE |
258 NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
259 .offs = 4,
260 .len = 4,
261 .veroffs = 20,
262 .maxblocks = 4,
263 .pattern = mirror_pattern
264};
265
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530266static u8 buf_data[READ_BUFF_SIZE];
267static u32 buf_index;
268
269static struct nand_ecclayout nand_oob;
270
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530271static void arasan_nand_select_chip(struct mtd_info *mtd, int chip)
272{
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700273 struct nand_chip *nand_chip = mtd_to_nand(mtd);
274 struct nand_drv *info = nand_get_controller_data(nand_chip);
T Karthik Reddy7cd85222018-12-03 16:11:58 +0530275 u32 reg_val;
276
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700277 reg_val = readl(&info->reg->memadr_reg2);
T Karthik Reddy7cd85222018-12-03 16:11:58 +0530278 if (chip == 0) {
279 reg_val &= ~ARASAN_NAND_MEM_ADDR2_CS0_MASK;
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700280 writel(reg_val, &info->reg->memadr_reg2);
T Karthik Reddy7cd85222018-12-03 16:11:58 +0530281 } else if (chip == 1) {
282 reg_val |= ARASAN_NAND_MEM_ADDR2_CS1_MASK;
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700283 writel(reg_val, &info->reg->memadr_reg2);
T Karthik Reddy7cd85222018-12-03 16:11:58 +0530284 }
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530285}
286
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700287static void arasan_nand_enable_ecc(struct mtd_info *mtd)
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530288{
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700289 struct nand_chip *chip = mtd_to_nand(mtd);
290 struct nand_drv *info = nand_get_controller_data(chip);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530291 u32 reg_val;
292
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700293 reg_val = readl(&info->reg->cmd_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530294 reg_val |= ARASAN_NAND_CMD_ECC_ON_MASK;
295
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700296 writel(reg_val, &info->reg->cmd_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530297}
298
299static u8 arasan_nand_get_addrcycle(struct mtd_info *mtd)
300{
301 u8 addrcycles;
Scott Wood17fed142016-05-30 13:57:56 -0500302 struct nand_chip *chip = mtd_to_nand(mtd);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530303
304 switch (curr_cmd->addr_cycles) {
305 case NAND_ADDR_CYCL_NONE:
306 addrcycles = 0;
307 break;
308 case NAND_ADDR_CYCL_ONE:
309 addrcycles = 1;
310 break;
311 case NAND_ADDR_CYCL_ROW:
312 addrcycles = chip->onfi_params.addr_cycles &
313 ARASAN_NAND_ROW_ADDR_CYCL_MASK;
314 break;
315 case NAND_ADDR_CYCL_COL:
316 addrcycles = (chip->onfi_params.addr_cycles &
317 ARASAN_NAND_COL_ADDR_CYCL_MASK) >>
318 ARASAN_NAND_COL_ADDR_CYCL_SHIFT;
319 break;
320 case NAND_ADDR_CYCL_BOTH:
321 addrcycles = chip->onfi_params.addr_cycles &
322 ARASAN_NAND_ROW_ADDR_CYCL_MASK;
323 addrcycles += (chip->onfi_params.addr_cycles &
324 ARASAN_NAND_COL_ADDR_CYCL_MASK) >>
325 ARASAN_NAND_COL_ADDR_CYCL_SHIFT;
326 break;
327 default:
328 addrcycles = ARASAN_NAND_INVALID_ADDR_CYCL;
329 break;
330 }
331 return addrcycles;
332}
333
334static int arasan_nand_read_page(struct mtd_info *mtd, u8 *buf, u32 size)
335{
Scott Wood17fed142016-05-30 13:57:56 -0500336 struct nand_chip *chip = mtd_to_nand(mtd);
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700337 struct nand_drv *info = nand_get_controller_data(chip);
338 struct nand_config *nand = &info->config;
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530339 u32 reg_val, i, pktsize, pktnum;
340 u32 *bufptr = (u32 *)buf;
341 u32 timeout;
342 u32 rdcount = 0;
343 u8 addr_cycles;
344
345 if (chip->ecc_step_ds >= ARASAN_NAND_PKTSIZE_1K)
346 pktsize = ARASAN_NAND_PKTSIZE_1K;
347 else
348 pktsize = ARASAN_NAND_PKTSIZE_512;
349
350 if (size % pktsize)
351 pktnum = size/pktsize + 1;
352 else
353 pktnum = size/pktsize;
354
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700355 reg_val = readl(&info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530356 reg_val |= ARASAN_NAND_INT_STS_ERR_EN_MASK |
357 ARASAN_NAND_INT_STS_MUL_BIT_ERR_MASK;
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700358 writel(reg_val, &info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530359
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700360 reg_val = readl(&info->reg->pkt_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530361 reg_val &= ~(ARASAN_NAND_PKT_REG_PKT_CNT_MASK |
362 ARASAN_NAND_PKT_REG_PKT_SIZE_MASK);
363 reg_val |= (pktnum << ARASAN_NAND_PKT_REG_PKT_CNT_SHFT) |
364 pktsize;
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700365 writel(reg_val, &info->reg->pkt_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530366
Siva Durga Prasad Paladugu45e512c2018-01-04 16:04:21 +0530367 if (!nand->on_die_ecc_enabled) {
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700368 arasan_nand_enable_ecc(mtd);
Siva Durga Prasad Paladugu45e512c2018-01-04 16:04:21 +0530369 addr_cycles = arasan_nand_get_addrcycle(mtd);
370 if (addr_cycles == ARASAN_NAND_INVALID_ADDR_CYCL)
371 return ERR_ADDR_CYCLE;
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530372
Siva Durga Prasad Paladugu45e512c2018-01-04 16:04:21 +0530373 writel((NAND_CMD_RNDOUTSTART << ARASAN_NAND_CMD_CMD2_SHIFT) |
374 NAND_CMD_RNDOUT | (addr_cycles <<
375 ARASAN_NAND_CMD_ADDR_CYCL_SHIFT),
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700376 &info->reg->ecc_sprcmd_reg);
Siva Durga Prasad Paladugu45e512c2018-01-04 16:04:21 +0530377 }
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700378 writel(curr_cmd->pgm, &info->reg->pgm_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530379
380 while (rdcount < pktnum) {
381 timeout = ARASAN_NAND_POLL_TIMEOUT;
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700382 while (!(readl(&info->reg->intsts_reg) &
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530383 ARASAN_NAND_INT_STS_BUF_RD_RDY_MASK) && timeout) {
384 udelay(1);
385 timeout--;
386 }
387 if (!timeout) {
388 puts("arasan_read_page: timedout:Buff RDY\n");
389 return -ETIMEDOUT;
390 }
391
392 rdcount++;
393
394 if (pktnum == rdcount) {
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700395 reg_val = readl(&info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530396 reg_val |= ARASAN_NAND_INT_STS_XFR_CMPLT_MASK;
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700397 writel(reg_val, &info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530398 } else {
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700399 reg_val = readl(&info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530400 writel(reg_val | ARASAN_NAND_INT_STS_BUF_RD_RDY_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700401 &info->reg->intsts_enr);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530402 }
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700403 reg_val = readl(&info->reg->intsts_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530404 writel(reg_val | ARASAN_NAND_INT_STS_BUF_RD_RDY_MASK,
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700405 &info->reg->intsts_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530406
407 for (i = 0; i < pktsize/4; i++)
Ashok Reddy Soma13e92302019-12-19 02:27:43 -0700408 bufptr[i] = readl(&info->reg->buf_dataport);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +0530409
410
411 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);
Ashok Reddy Somac7b66332019-12-19 02:27:42 -07001123 struct nand_config *nand = nand_get_controller_data(nand_chip);
Siva Durga Prasad Paladugu45e512c2018-01-04 16:04:21 +05301124 u8 maf_id, dev_id;
1125 u8 get_feature[4];
1126 u8 set_feature[4] = {ENABLE_ONDIE_ECC, 0x00, 0x00, 0x00};
1127 u32 i;
1128
1129 /* Send the command for reading device ID */
1130 nand_chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
1131 nand_chip->cmdfunc(mtd, NAND_CMD_READID, 0, -1);
1132
1133 /* Read manufacturer and device IDs */
1134 maf_id = nand_chip->read_byte(mtd);
1135 dev_id = nand_chip->read_byte(mtd);
1136
1137 if ((maf_id == NAND_MFR_MICRON) &&
1138 ((dev_id == 0xf1) || (dev_id == 0xa1) || (dev_id == 0xb1) ||
1139 (dev_id == 0xaa) || (dev_id == 0xba) || (dev_id == 0xda) ||
1140 (dev_id == 0xca) || (dev_id == 0xac) || (dev_id == 0xbc) ||
1141 (dev_id == 0xdc) || (dev_id == 0xcc) || (dev_id == 0xa3) ||
1142 (dev_id == 0xb3) || (dev_id == 0xd3) || (dev_id == 0xc3))) {
1143 nand_chip->cmdfunc(mtd, NAND_CMD_SET_FEATURES,
1144 ONDIE_ECC_FEATURE_ADDR, -1);
1145
1146 nand_chip->write_buf(mtd, &set_feature[0], 4);
1147 nand_chip->cmdfunc(mtd, NAND_CMD_GET_FEATURES,
1148 ONDIE_ECC_FEATURE_ADDR, -1);
1149
1150 for (i = 0; i < 4; i++)
1151 get_feature[i] = nand_chip->read_byte(mtd);
1152
1153 if (get_feature[0] & ENABLE_ONDIE_ECC)
1154 nand->on_die_ecc_enabled = true;
1155 else
1156 printf("%s: Unable to enable OnDie ECC\n", __func__);
1157
1158 /* Use the BBT pattern descriptors */
1159 nand_chip->bbt_td = &bbt_main_descr;
1160 nand_chip->bbt_md = &bbt_mirror_descr;
1161 }
1162}
1163
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301164static int arasan_nand_ecc_init(struct mtd_info *mtd)
1165{
Ashok Reddy Soma13e92302019-12-19 02:27:43 -07001166 struct nand_chip *nand_chip = mtd_to_nand(mtd);
1167 struct nand_drv *info = nand_get_controller_data(nand_chip);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301168 int found = -1;
Siva Durga Prasad Paladugub0a4f132018-01-04 16:04:22 +05301169 u32 regval, eccpos_start, i, eccaddr;
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301170
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301171 for (i = 0; i < ARRAY_SIZE(ecc_matrix); i++) {
1172 if ((ecc_matrix[i].pagesize == mtd->writesize) &&
1173 (ecc_matrix[i].ecc_codeword_size >=
1174 nand_chip->ecc_step_ds)) {
1175 if (ecc_matrix[i].eccbits >=
1176 nand_chip->ecc_strength_ds) {
1177 found = i;
1178 break;
1179 }
1180 found = i;
1181 }
1182 }
1183
1184 if (found < 0)
1185 return 1;
1186
Siva Durga Prasad Paladugub0a4f132018-01-04 16:04:22 +05301187 eccaddr = mtd->writesize + mtd->oobsize -
1188 ecc_matrix[found].eccsize;
1189
1190 regval = eccaddr |
Siva Durga Prasad Paladugudb796632016-05-25 15:20:38 +05301191 (ecc_matrix[found].eccsize << ARASAN_NAND_ECC_SIZE_SHIFT) |
1192 (ecc_matrix[found].bch << ARASAN_NAND_ECC_BCH_SHIFT);
Ashok Reddy Soma13e92302019-12-19 02:27:43 -07001193 writel(regval, &info->reg->ecc_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301194
Siva Durga Prasad Paladugudb796632016-05-25 15:20:38 +05301195 if (ecc_matrix[found].bch) {
Ashok Reddy Soma13e92302019-12-19 02:27:43 -07001196 regval = readl(&info->reg->memadr_reg2);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301197 regval &= ~ARASAN_NAND_MEM_ADDR2_BCH_MASK;
Siva Durga Prasad Paladugudb796632016-05-25 15:20:38 +05301198 regval |= (ecc_matrix[found].bchval <<
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301199 ARASAN_NAND_MEM_ADDR2_BCH_SHIFT);
Ashok Reddy Soma13e92302019-12-19 02:27:43 -07001200 writel(regval, &info->reg->memadr_reg2);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301201 }
1202
Siva Durga Prasad Paladugudb796632016-05-25 15:20:38 +05301203 nand_oob.eccbytes = ecc_matrix[found].eccsize;
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301204 eccpos_start = mtd->oobsize - nand_oob.eccbytes;
1205
1206 for (i = 0; i < nand_oob.eccbytes; i++)
1207 nand_oob.eccpos[i] = eccpos_start + i;
1208
1209 nand_oob.oobfree[0].offset = 2;
1210 nand_oob.oobfree[0].length = eccpos_start - 2;
1211
Siva Durga Prasad Paladugudb796632016-05-25 15:20:38 +05301212 nand_chip->ecc.size = ecc_matrix[found].ecc_codeword_size;
1213 nand_chip->ecc.strength = ecc_matrix[found].eccbits;
1214 nand_chip->ecc.bytes = ecc_matrix[found].eccsize;
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301215 nand_chip->ecc.layout = &nand_oob;
1216
1217 return 0;
1218}
1219
Ashok Reddy Somac7b66332019-12-19 02:27:42 -07001220static int arasan_probe(struct udevice *dev)
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301221{
Ashok Reddy Somac7b66332019-12-19 02:27:42 -07001222 struct arasan_nand_info *arasan = dev_get_priv(dev);
1223 struct nand_chip *nand_chip = &arasan->nand_chip;
Ashok Reddy Soma13e92302019-12-19 02:27:43 -07001224 struct nand_drv *info = &arasan->nand_ctrl;
1225 struct nand_config *nand = &info->config;
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301226 struct mtd_info *mtd;
1227 int err = -1;
1228
Ashok Reddy Soma13e92302019-12-19 02:27:43 -07001229 info->reg = (struct nand_regs *)dev_read_addr(dev);
Scott Wood17fed142016-05-30 13:57:56 -05001230 mtd = nand_to_mtd(nand_chip);
Ashok Reddy Soma13e92302019-12-19 02:27:43 -07001231 nand_set_controller_data(nand_chip, &arasan->nand_ctrl);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301232
Martin Lund5f9ae0e2018-10-30 14:16:19 +01001233#ifdef CONFIG_SYS_NAND_NO_SUBPAGE_WRITE
1234 nand_chip->options |= NAND_NO_SUBPAGE_WRITE;
1235#endif
1236
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301237 /* Set the driver entry points for MTD */
1238 nand_chip->cmdfunc = arasan_nand_cmd_function;
1239 nand_chip->select_chip = arasan_nand_select_chip;
1240 nand_chip->read_byte = arasan_nand_read_byte;
1241
1242 /* Buffer read/write routines */
1243 nand_chip->read_buf = arasan_nand_read_buf;
1244 nand_chip->write_buf = arasan_nand_write_buf;
1245 nand_chip->bbt_options = NAND_BBT_USE_FLASH;
1246
Ashok Reddy Soma13e92302019-12-19 02:27:43 -07001247 writel(0x0, &info->reg->cmd_reg);
1248 writel(0x0, &info->reg->pgm_reg);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301249
1250 /* first scan to find the device and get the page size */
T Karthik Reddy7cd85222018-12-03 16:11:58 +05301251 if (nand_scan_ident(mtd, CONFIG_SYS_NAND_MAX_CHIPS, NULL)) {
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301252 printf("%s: nand_scan_ident failed\n", __func__);
1253 goto fail;
1254 }
1255
Siva Durga Prasad Paladugu80c889c2018-01-04 16:04:20 +05301256 nand_chip->ecc.mode = NAND_ECC_HW;
1257 nand_chip->ecc.hwctl = NULL;
1258 nand_chip->ecc.read_page = arasan_nand_read_page_hwecc;
1259 nand_chip->ecc.write_page = arasan_nand_write_page_hwecc;
1260 nand_chip->ecc.read_oob = arasan_nand_read_oob;
1261 nand_chip->ecc.write_oob = arasan_nand_write_oob;
1262
Siva Durga Prasad Paladugu45e512c2018-01-04 16:04:21 +05301263 arasan_check_ondie(mtd);
1264
1265 /*
1266 * If on die supported, then give priority to on-die ecc and use
1267 * it instead of controller ecc.
1268 */
1269 if (nand->on_die_ecc_enabled) {
1270 nand_chip->ecc.strength = 1;
1271 nand_chip->ecc.size = mtd->writesize;
1272 nand_chip->ecc.bytes = 0;
1273 nand_chip->ecc.layout = &ondie_nand_oob_64;
1274 } else {
1275 if (arasan_nand_ecc_init(mtd)) {
1276 printf("%s: nand_ecc_init failed\n", __func__);
1277 goto fail;
1278 }
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301279 }
1280
1281 if (nand_scan_tail(mtd)) {
1282 printf("%s: nand_scan_tail failed\n", __func__);
1283 goto fail;
1284 }
1285
Ashok Reddy Somac7b66332019-12-19 02:27:42 -07001286 if (nand_register(0, mtd)) {
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301287 printf("Nand Register Fail\n");
1288 goto fail;
1289 }
1290
1291 return 0;
1292fail:
1293 free(nand);
1294 return err;
1295}
1296
Ashok Reddy Somac7b66332019-12-19 02:27:42 -07001297static const struct udevice_id arasan_nand_dt_ids[] = {
1298 {.compatible = "arasan,nfc-v3p10",},
1299 { /* sentinel */ }
1300};
1301
1302U_BOOT_DRIVER(arasan_nand) = {
1303 .name = "arasan-nand",
1304 .id = UCLASS_MTD,
1305 .of_match = arasan_nand_dt_ids,
1306 .probe = arasan_probe,
1307 .priv_auto_alloc_size = sizeof(struct arasan_nand_info),
1308};
1309
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301310void board_nand_init(void)
1311{
Ashok Reddy Somac7b66332019-12-19 02:27:42 -07001312 struct udevice *dev;
1313 int ret;
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301314
Ashok Reddy Somac7b66332019-12-19 02:27:42 -07001315 ret = uclass_get_device_by_driver(UCLASS_MTD,
1316 DM_GET_DRIVER(arasan_nand), &dev);
1317 if (ret && ret != -ENODEV)
1318 pr_err("Failed to initialize %s. (error %d)\n", dev->name, ret);
Siva Durga Prasad Paladuguc7b0bc72015-11-17 14:30:10 +05301319}