blob: 1d7c1fddd3f64b7f3614b32e9aa0ca4b9cbf82a3 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Dipen Dudhat9eae0832011-03-22 09:27:39 +05302/* Integrated Flash Controller NAND Machine Driver
3 *
Prabhakar Kushwahacdd045d2012-01-20 18:38:14 +05304 * Copyright (c) 2012 Freescale Semiconductor, Inc
Dipen Dudhat9eae0832011-03-22 09:27:39 +05305 *
6 * Authors: Dipen Dudhat <Dipen.Dudhat@freescale.com>
Dipen Dudhat9eae0832011-03-22 09:27:39 +05307 */
8
9#include <common.h>
Simon Glassadaaa482019-11-14 12:57:43 -070010#include <command.h>
Dipen Dudhat9eae0832011-03-22 09:27:39 +053011#include <malloc.h>
Prabhakar Kushwaha895d0392013-04-04 18:44:06 +000012#include <nand.h>
Simon Glassd66c5f72020-02-03 07:36:15 -070013#include <dm/devres.h>
Dipen Dudhat9eae0832011-03-22 09:27:39 +053014
15#include <linux/mtd/mtd.h>
Masahiro Yamada2b7a8732017-11-30 13:45:24 +090016#include <linux/mtd/rawnand.h>
Dipen Dudhat9eae0832011-03-22 09:27:39 +053017#include <linux/mtd/nand_ecc.h>
18
19#include <asm/io.h>
Masahiro Yamada56a931c2016-09-21 11:28:55 +090020#include <linux/errno.h>
York Sun37562f62013-10-22 12:39:02 -070021#include <fsl_ifc.h>
Dipen Dudhat9eae0832011-03-22 09:27:39 +053022
Prabhakar Kushwahaa8759642014-06-12 09:13:08 +053023#define MAX_BANKS CONFIG_SYS_FSL_IFC_BANK_COUNT
Dipen Dudhat9eae0832011-03-22 09:27:39 +053024#define ERR_BYTE 0xFF /* Value returned for read bytes
25 when read failed */
Dipen Dudhat9eae0832011-03-22 09:27:39 +053026
27struct fsl_ifc_ctrl;
28
29/* mtd information per set */
30struct fsl_ifc_mtd {
Dipen Dudhat9eae0832011-03-22 09:27:39 +053031 struct nand_chip chip;
32 struct fsl_ifc_ctrl *ctrl;
33
34 struct device *dev;
35 int bank; /* Chip select bank number */
36 unsigned int bufnum_mask; /* bufnum = page & bufnum_mask */
37 u8 __iomem *vbase; /* Chip select base virtual address */
38};
39
40/* overview of the fsl ifc controller */
41struct fsl_ifc_ctrl {
42 struct nand_hw_control controller;
43 struct fsl_ifc_mtd *chips[MAX_BANKS];
44
45 /* device info */
Jaiprakash Singhdd888062015-03-20 19:28:27 -070046 struct fsl_ifc regs;
Scott Wood3ea94ed2015-06-26 19:03:26 -050047 void __iomem *addr; /* Address of assigned IFC buffer */
Dipen Dudhat9eae0832011-03-22 09:27:39 +053048 unsigned int page; /* Last page written to / read from */
49 unsigned int read_bytes; /* Number of bytes read during command */
50 unsigned int column; /* Saved column from SEQIN */
51 unsigned int index; /* Pointer to next byte to 'read' */
52 unsigned int status; /* status read from NEESR after last op */
53 unsigned int oob; /* Non zero if operating on OOB data */
54 unsigned int eccread; /* Non zero for a full-page ECC read */
55};
56
57static struct fsl_ifc_ctrl *ifc_ctrl;
58
59/* 512-byte page with 4-bit ECC, 8-bit */
60static struct nand_ecclayout oob_512_8bit_ecc4 = {
61 .eccbytes = 8,
62 .eccpos = {8, 9, 10, 11, 12, 13, 14, 15},
63 .oobfree = { {0, 5}, {6, 2} },
64};
65
66/* 512-byte page with 4-bit ECC, 16-bit */
67static struct nand_ecclayout oob_512_16bit_ecc4 = {
68 .eccbytes = 8,
69 .eccpos = {8, 9, 10, 11, 12, 13, 14, 15},
70 .oobfree = { {2, 6}, },
71};
72
73/* 2048-byte page size with 4-bit ECC */
74static struct nand_ecclayout oob_2048_ecc4 = {
75 .eccbytes = 32,
76 .eccpos = {
77 8, 9, 10, 11, 12, 13, 14, 15,
78 16, 17, 18, 19, 20, 21, 22, 23,
79 24, 25, 26, 27, 28, 29, 30, 31,
80 32, 33, 34, 35, 36, 37, 38, 39,
81 },
82 .oobfree = { {2, 6}, {40, 24} },
83};
84
85/* 4096-byte page size with 4-bit ECC */
86static struct nand_ecclayout oob_4096_ecc4 = {
87 .eccbytes = 64,
88 .eccpos = {
89 8, 9, 10, 11, 12, 13, 14, 15,
90 16, 17, 18, 19, 20, 21, 22, 23,
91 24, 25, 26, 27, 28, 29, 30, 31,
92 32, 33, 34, 35, 36, 37, 38, 39,
93 40, 41, 42, 43, 44, 45, 46, 47,
94 48, 49, 50, 51, 52, 53, 54, 55,
95 56, 57, 58, 59, 60, 61, 62, 63,
96 64, 65, 66, 67, 68, 69, 70, 71,
97 },
98 .oobfree = { {2, 6}, {72, 56} },
99};
100
101/* 4096-byte page size with 8-bit ECC -- requires 218-byte OOB */
102static struct nand_ecclayout oob_4096_ecc8 = {
103 .eccbytes = 128,
104 .eccpos = {
105 8, 9, 10, 11, 12, 13, 14, 15,
106 16, 17, 18, 19, 20, 21, 22, 23,
107 24, 25, 26, 27, 28, 29, 30, 31,
108 32, 33, 34, 35, 36, 37, 38, 39,
109 40, 41, 42, 43, 44, 45, 46, 47,
110 48, 49, 50, 51, 52, 53, 54, 55,
111 56, 57, 58, 59, 60, 61, 62, 63,
112 64, 65, 66, 67, 68, 69, 70, 71,
113 72, 73, 74, 75, 76, 77, 78, 79,
114 80, 81, 82, 83, 84, 85, 86, 87,
115 88, 89, 90, 91, 92, 93, 94, 95,
116 96, 97, 98, 99, 100, 101, 102, 103,
117 104, 105, 106, 107, 108, 109, 110, 111,
118 112, 113, 114, 115, 116, 117, 118, 119,
119 120, 121, 122, 123, 124, 125, 126, 127,
120 128, 129, 130, 131, 132, 133, 134, 135,
121 },
122 .oobfree = { {2, 6}, {136, 82} },
123};
124
Prabhakar Kushwahaa3aaf1d2013-10-04 10:05:36 +0530125/* 8192-byte page size with 4-bit ECC */
126static struct nand_ecclayout oob_8192_ecc4 = {
127 .eccbytes = 128,
128 .eccpos = {
129 8, 9, 10, 11, 12, 13, 14, 15,
130 16, 17, 18, 19, 20, 21, 22, 23,
131 24, 25, 26, 27, 28, 29, 30, 31,
132 32, 33, 34, 35, 36, 37, 38, 39,
133 40, 41, 42, 43, 44, 45, 46, 47,
134 48, 49, 50, 51, 52, 53, 54, 55,
135 56, 57, 58, 59, 60, 61, 62, 63,
136 64, 65, 66, 67, 68, 69, 70, 71,
137 72, 73, 74, 75, 76, 77, 78, 79,
138 80, 81, 82, 83, 84, 85, 86, 87,
139 88, 89, 90, 91, 92, 93, 94, 95,
140 96, 97, 98, 99, 100, 101, 102, 103,
141 104, 105, 106, 107, 108, 109, 110, 111,
142 112, 113, 114, 115, 116, 117, 118, 119,
143 120, 121, 122, 123, 124, 125, 126, 127,
144 128, 129, 130, 131, 132, 133, 134, 135,
145 },
146 .oobfree = { {2, 6}, {136, 208} },
147};
148
149/* 8192-byte page size with 8-bit ECC -- requires 218-byte OOB */
150static struct nand_ecclayout oob_8192_ecc8 = {
151 .eccbytes = 256,
152 .eccpos = {
153 8, 9, 10, 11, 12, 13, 14, 15,
154 16, 17, 18, 19, 20, 21, 22, 23,
155 24, 25, 26, 27, 28, 29, 30, 31,
156 32, 33, 34, 35, 36, 37, 38, 39,
157 40, 41, 42, 43, 44, 45, 46, 47,
158 48, 49, 50, 51, 52, 53, 54, 55,
159 56, 57, 58, 59, 60, 61, 62, 63,
160 64, 65, 66, 67, 68, 69, 70, 71,
161 72, 73, 74, 75, 76, 77, 78, 79,
162 80, 81, 82, 83, 84, 85, 86, 87,
163 88, 89, 90, 91, 92, 93, 94, 95,
164 96, 97, 98, 99, 100, 101, 102, 103,
165 104, 105, 106, 107, 108, 109, 110, 111,
166 112, 113, 114, 115, 116, 117, 118, 119,
167 120, 121, 122, 123, 124, 125, 126, 127,
168 128, 129, 130, 131, 132, 133, 134, 135,
169 136, 137, 138, 139, 140, 141, 142, 143,
170 144, 145, 146, 147, 148, 149, 150, 151,
171 152, 153, 154, 155, 156, 157, 158, 159,
172 160, 161, 162, 163, 164, 165, 166, 167,
173 168, 169, 170, 171, 172, 173, 174, 175,
174 176, 177, 178, 179, 180, 181, 182, 183,
175 184, 185, 186, 187, 188, 189, 190, 191,
176 192, 193, 194, 195, 196, 197, 198, 199,
177 200, 201, 202, 203, 204, 205, 206, 207,
178 208, 209, 210, 211, 212, 213, 214, 215,
179 216, 217, 218, 219, 220, 221, 222, 223,
180 224, 225, 226, 227, 228, 229, 230, 231,
181 232, 233, 234, 235, 236, 237, 238, 239,
182 240, 241, 242, 243, 244, 245, 246, 247,
183 248, 249, 250, 251, 252, 253, 254, 255,
184 256, 257, 258, 259, 260, 261, 262, 263,
185 },
186 .oobfree = { {2, 6}, {264, 80} },
187};
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530188
189/*
190 * Generic flash bbt descriptors
191 */
192static u8 bbt_pattern[] = {'B', 'b', 't', '0' };
193static u8 mirror_pattern[] = {'1', 't', 'b', 'B' };
194
195static struct nand_bbt_descr bbt_main_descr = {
196 .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE |
197 NAND_BBT_2BIT | NAND_BBT_VERSION,
198 .offs = 2, /* 0 on 8-bit small page */
199 .len = 4,
200 .veroffs = 6,
201 .maxblocks = 4,
202 .pattern = bbt_pattern,
203};
204
205static struct nand_bbt_descr bbt_mirror_descr = {
206 .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE |
207 NAND_BBT_2BIT | NAND_BBT_VERSION,
208 .offs = 2, /* 0 on 8-bit small page */
209 .len = 4,
210 .veroffs = 6,
211 .maxblocks = 4,
212 .pattern = mirror_pattern,
213};
214
215/*
216 * Set up the IFC hardware block and page address fields, and the ifc nand
217 * structure addr field to point to the correct IFC buffer in memory
218 */
219static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob)
220{
Scott Wood17fed142016-05-30 13:57:56 -0500221 struct nand_chip *chip = mtd_to_nand(mtd);
222 struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530223 struct fsl_ifc_ctrl *ctrl = priv->ctrl;
Jaiprakash Singhdd888062015-03-20 19:28:27 -0700224 struct fsl_ifc_runtime *ifc = ctrl->regs.rregs;
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530225 int buf_num;
226
227 ctrl->page = page_addr;
228
229 /* Program ROW0/COL0 */
Prabhakar Kushwaha62908c22014-01-18 12:28:30 +0530230 ifc_out32(&ifc->ifc_nand.row0, page_addr);
231 ifc_out32(&ifc->ifc_nand.col0, (oob ? IFC_NAND_COL_MS : 0) | column);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530232
233 buf_num = page_addr & priv->bufnum_mask;
234
235 ctrl->addr = priv->vbase + buf_num * (mtd->writesize * 2);
236 ctrl->index = column;
237
238 /* for OOB data point to the second half of the buffer */
239 if (oob)
240 ctrl->index += mtd->writesize;
241}
242
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530243/* returns nonzero if entire page is blank */
244static int check_read_ecc(struct mtd_info *mtd, struct fsl_ifc_ctrl *ctrl,
Jagdish Gediya83fbe912018-03-24 02:55:51 +0530245 u32 eccstat, unsigned int bufnum)
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530246{
Jagdish Gediya83fbe912018-03-24 02:55:51 +0530247 return (eccstat >> ((3 - bufnum % 4) * 8)) & 15;
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530248}
249
250/*
251 * execute IFC NAND command and wait for it to complete
252 */
253static int fsl_ifc_run_command(struct mtd_info *mtd)
254{
Scott Wood17fed142016-05-30 13:57:56 -0500255 struct nand_chip *chip = mtd_to_nand(mtd);
256 struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530257 struct fsl_ifc_ctrl *ctrl = priv->ctrl;
Jaiprakash Singhdd888062015-03-20 19:28:27 -0700258 struct fsl_ifc_runtime *ifc = ctrl->regs.rregs;
Prabhakar Kushwahad7550e12014-09-23 09:57:47 +0530259 u32 timeo = (CONFIG_SYS_HZ * 10) / 1000;
260 u32 time_start;
Jagdish Gediya83fbe912018-03-24 02:55:51 +0530261 u32 eccstat;
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530262 int i;
263
264 /* set the chip select for NAND Transaction */
Kurt Kanzenbach1f161f82017-10-20 11:44:25 +0200265 ifc_out32(&ifc->ifc_nand.nand_csel, priv->bank << IFC_NAND_CSEL_SHIFT);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530266
267 /* start read/write seq */
Prabhakar Kushwaha62908c22014-01-18 12:28:30 +0530268 ifc_out32(&ifc->ifc_nand.nandseq_strt,
269 IFC_NAND_SEQ_STRT_FIR_STRT);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530270
271 /* wait for NAND Machine complete flag or timeout */
Prabhakar Kushwahad7550e12014-09-23 09:57:47 +0530272 time_start = get_timer(0);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530273
Prabhakar Kushwahad7550e12014-09-23 09:57:47 +0530274 while (get_timer(time_start) < timeo) {
Prabhakar Kushwaha62908c22014-01-18 12:28:30 +0530275 ctrl->status = ifc_in32(&ifc->ifc_nand.nand_evter_stat);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530276
277 if (ctrl->status & IFC_NAND_EVTER_STAT_OPC)
278 break;
279 }
280
Prabhakar Kushwaha62908c22014-01-18 12:28:30 +0530281 ifc_out32(&ifc->ifc_nand.nand_evter_stat, ctrl->status);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530282
283 if (ctrl->status & IFC_NAND_EVTER_STAT_FTOER)
284 printf("%s: Flash Time Out Error\n", __func__);
285 if (ctrl->status & IFC_NAND_EVTER_STAT_WPER)
286 printf("%s: Write Protect Error\n", __func__);
287
288 if (ctrl->eccread) {
Prabhakar Kushwahacdd045d2012-01-20 18:38:14 +0530289 int errors;
290 int bufnum = ctrl->page & priv->bufnum_mask;
Jagdish Gediya83fbe912018-03-24 02:55:51 +0530291 int sector_start = bufnum * chip->ecc.steps;
292 int sector_end = sector_start + chip->ecc.steps - 1;
293 u32 *eccstat_regs;
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530294
Jagdish Gediya83fbe912018-03-24 02:55:51 +0530295 eccstat_regs = ifc->ifc_nand.nand_eccstat;
296 eccstat = ifc_in32(&eccstat_regs[sector_start / 4]);
Scott Wood70365492015-03-19 09:20:49 -0700297
Jagdish Gediya83fbe912018-03-24 02:55:51 +0530298 for (i = sector_start; i <= sector_end; i++) {
299 if ((i != sector_start) && !(i % 4))
300 eccstat = ifc_in32(&eccstat_regs[i / 4]);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530301
Prabhakar Kushwahacdd045d2012-01-20 18:38:14 +0530302 errors = check_read_ecc(mtd, ctrl, eccstat, i);
303
304 if (errors == 15) {
305 /*
306 * Uncorrectable error.
Darwin Dingel3dae7e62018-08-02 10:02:45 +0200307 * We'll check for blank pages later.
Prabhakar Kushwahacdd045d2012-01-20 18:38:14 +0530308 *
309 * We disable ECCER reporting due to erratum
310 * IFC-A002770 -- so report it now if we
311 * see an uncorrectable error in ECCSTAT.
312 */
Darwin Dingel3dae7e62018-08-02 10:02:45 +0200313 ctrl->status |= IFC_NAND_EVTER_STAT_ECCER;
314 continue;
Prabhakar Kushwahacdd045d2012-01-20 18:38:14 +0530315 }
316
317 mtd->ecc_stats.corrected += errors;
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530318 }
319
320 ctrl->eccread = 0;
321 }
322
323 /* returns 0 on success otherwise non-zero) */
324 return ctrl->status == IFC_NAND_EVTER_STAT_OPC ? 0 : -EIO;
325}
326
327static void fsl_ifc_do_read(struct nand_chip *chip,
328 int oob,
329 struct mtd_info *mtd)
330{
Scott Wood17fed142016-05-30 13:57:56 -0500331 struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530332 struct fsl_ifc_ctrl *ctrl = priv->ctrl;
Jaiprakash Singhdd888062015-03-20 19:28:27 -0700333 struct fsl_ifc_runtime *ifc = ctrl->regs.rregs;
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530334
335 /* Program FIR/IFC_NAND_FCR0 for Small/Large page */
336 if (mtd->writesize > 512) {
Prabhakar Kushwaha62908c22014-01-18 12:28:30 +0530337 ifc_out32(&ifc->ifc_nand.nand_fir0,
338 (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
339 (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) |
340 (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP2_SHIFT) |
341 (IFC_FIR_OP_CMD1 << IFC_NAND_FIR0_OP3_SHIFT) |
342 (IFC_FIR_OP_RBCD << IFC_NAND_FIR0_OP4_SHIFT));
343 ifc_out32(&ifc->ifc_nand.nand_fir1, 0x0);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530344
Prabhakar Kushwaha62908c22014-01-18 12:28:30 +0530345 ifc_out32(&ifc->ifc_nand.nand_fcr0,
346 (NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT) |
347 (NAND_CMD_READSTART << IFC_NAND_FCR0_CMD1_SHIFT));
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530348 } else {
Prabhakar Kushwaha62908c22014-01-18 12:28:30 +0530349 ifc_out32(&ifc->ifc_nand.nand_fir0,
350 (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
351 (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) |
352 (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP2_SHIFT) |
353 (IFC_FIR_OP_RBCD << IFC_NAND_FIR0_OP3_SHIFT));
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530354
355 if (oob)
Prabhakar Kushwaha62908c22014-01-18 12:28:30 +0530356 ifc_out32(&ifc->ifc_nand.nand_fcr0,
357 NAND_CMD_READOOB << IFC_NAND_FCR0_CMD0_SHIFT);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530358 else
Prabhakar Kushwaha62908c22014-01-18 12:28:30 +0530359 ifc_out32(&ifc->ifc_nand.nand_fcr0,
360 NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530361 }
362}
363
364/* cmdfunc send commands to the IFC NAND Machine */
365static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command,
366 int column, int page_addr)
367{
Scott Wood17fed142016-05-30 13:57:56 -0500368 struct nand_chip *chip = mtd_to_nand(mtd);
369 struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530370 struct fsl_ifc_ctrl *ctrl = priv->ctrl;
Jaiprakash Singhdd888062015-03-20 19:28:27 -0700371 struct fsl_ifc_runtime *ifc = ctrl->regs.rregs;
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530372
373 /* clear the read buffer */
374 ctrl->read_bytes = 0;
375 if (command != NAND_CMD_PAGEPROG)
376 ctrl->index = 0;
377
378 switch (command) {
379 /* READ0 read the entire buffer to use hardware ECC. */
380 case NAND_CMD_READ0: {
Prabhakar Kushwaha62908c22014-01-18 12:28:30 +0530381 ifc_out32(&ifc->ifc_nand.nand_fbcr, 0);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530382 set_addr(mtd, 0, page_addr, 0);
383
384 ctrl->read_bytes = mtd->writesize + mtd->oobsize;
385 ctrl->index += column;
386
387 if (chip->ecc.mode == NAND_ECC_HW)
388 ctrl->eccread = 1;
389
390 fsl_ifc_do_read(chip, 0, mtd);
391 fsl_ifc_run_command(mtd);
392 return;
393 }
394
395 /* READOOB reads only the OOB because no ECC is performed. */
396 case NAND_CMD_READOOB:
Prabhakar Kushwaha62908c22014-01-18 12:28:30 +0530397 ifc_out32(&ifc->ifc_nand.nand_fbcr, mtd->oobsize - column);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530398 set_addr(mtd, column, page_addr, 1);
399
400 ctrl->read_bytes = mtd->writesize + mtd->oobsize;
401
402 fsl_ifc_do_read(chip, 1, mtd);
403 fsl_ifc_run_command(mtd);
404
405 return;
406
407 /* READID must read all possible bytes while CEB is active */
408 case NAND_CMD_READID:
Prabhakar Kushwahaf31cf532012-04-08 18:57:18 +0000409 case NAND_CMD_PARAM: {
Maxim Kochetkovfce4f4d2021-03-12 09:27:41 +0300410 /*
411 * For READID, read 8 bytes that are currently used.
412 * For PARAM, read all 3 copies of 256-bytes pages.
413 */
414 int len = 8;
Prabhakar Kushwahaf31cf532012-04-08 18:57:18 +0000415 int timing = IFC_FIR_OP_RB;
Maxim Kochetkovfce4f4d2021-03-12 09:27:41 +0300416 if (command == NAND_CMD_PARAM) {
Prabhakar Kushwahaf31cf532012-04-08 18:57:18 +0000417 timing = IFC_FIR_OP_RBCD;
Maxim Kochetkovfce4f4d2021-03-12 09:27:41 +0300418 len = 256 * 3;
419 }
Prabhakar Kushwahaf31cf532012-04-08 18:57:18 +0000420
Prabhakar Kushwaha62908c22014-01-18 12:28:30 +0530421 ifc_out32(&ifc->ifc_nand.nand_fir0,
422 (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
423 (IFC_FIR_OP_UA << IFC_NAND_FIR0_OP1_SHIFT) |
424 (timing << IFC_NAND_FIR0_OP2_SHIFT));
425 ifc_out32(&ifc->ifc_nand.nand_fcr0,
426 command << IFC_NAND_FCR0_CMD0_SHIFT);
427 ifc_out32(&ifc->ifc_nand.row3, column);
Prabhakar Kushwahaf31cf532012-04-08 18:57:18 +0000428
Maxim Kochetkovfce4f4d2021-03-12 09:27:41 +0300429 ifc_out32(&ifc->ifc_nand.nand_fbcr, len);
430 ctrl->read_bytes = len;
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530431
432 set_addr(mtd, 0, 0, 0);
433 fsl_ifc_run_command(mtd);
434 return;
Prabhakar Kushwahaf31cf532012-04-08 18:57:18 +0000435 }
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530436
437 /* ERASE1 stores the block and page address */
438 case NAND_CMD_ERASE1:
439 set_addr(mtd, 0, page_addr, 0);
440 return;
441
442 /* ERASE2 uses the block and page address from ERASE1 */
443 case NAND_CMD_ERASE2:
Prabhakar Kushwaha62908c22014-01-18 12:28:30 +0530444 ifc_out32(&ifc->ifc_nand.nand_fir0,
445 (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
446 (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP1_SHIFT) |
447 (IFC_FIR_OP_CMD1 << IFC_NAND_FIR0_OP2_SHIFT));
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530448
Prabhakar Kushwaha62908c22014-01-18 12:28:30 +0530449 ifc_out32(&ifc->ifc_nand.nand_fcr0,
450 (NAND_CMD_ERASE1 << IFC_NAND_FCR0_CMD0_SHIFT) |
451 (NAND_CMD_ERASE2 << IFC_NAND_FCR0_CMD1_SHIFT));
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530452
Prabhakar Kushwaha62908c22014-01-18 12:28:30 +0530453 ifc_out32(&ifc->ifc_nand.nand_fbcr, 0);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530454 ctrl->read_bytes = 0;
455 fsl_ifc_run_command(mtd);
456 return;
457
458 /* SEQIN sets up the addr buffer and all registers except the length */
459 case NAND_CMD_SEQIN: {
460 u32 nand_fcr0;
461 ctrl->column = column;
462 ctrl->oob = 0;
463
464 if (mtd->writesize > 512) {
465 nand_fcr0 =
466 (NAND_CMD_SEQIN << IFC_NAND_FCR0_CMD0_SHIFT) |
Prabhakar Kushwaha18e6bde2013-10-03 11:35:35 +0530467 (NAND_CMD_STATUS << IFC_NAND_FCR0_CMD1_SHIFT) |
468 (NAND_CMD_PAGEPROG << IFC_NAND_FCR0_CMD2_SHIFT);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530469
Prabhakar Kushwaha62908c22014-01-18 12:28:30 +0530470 ifc_out32(&ifc->ifc_nand.nand_fir0,
471 (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
472 (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) |
473 (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP2_SHIFT) |
474 (IFC_FIR_OP_WBCD <<
475 IFC_NAND_FIR0_OP3_SHIFT) |
476 (IFC_FIR_OP_CMD2 << IFC_NAND_FIR0_OP4_SHIFT));
477 ifc_out32(&ifc->ifc_nand.nand_fir1,
478 (IFC_FIR_OP_CW1 << IFC_NAND_FIR1_OP5_SHIFT) |
479 (IFC_FIR_OP_RDSTAT <<
Prabhakar Kushwaha18e6bde2013-10-03 11:35:35 +0530480 IFC_NAND_FIR1_OP6_SHIFT) |
Prabhakar Kushwaha62908c22014-01-18 12:28:30 +0530481 (IFC_FIR_OP_NOP << IFC_NAND_FIR1_OP7_SHIFT));
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530482 } else {
483 nand_fcr0 = ((NAND_CMD_PAGEPROG <<
484 IFC_NAND_FCR0_CMD1_SHIFT) |
485 (NAND_CMD_SEQIN <<
Prabhakar Kushwaha18e6bde2013-10-03 11:35:35 +0530486 IFC_NAND_FCR0_CMD2_SHIFT) |
487 (NAND_CMD_STATUS <<
488 IFC_NAND_FCR0_CMD3_SHIFT));
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530489
Prabhakar Kushwaha62908c22014-01-18 12:28:30 +0530490 ifc_out32(&ifc->ifc_nand.nand_fir0,
491 (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
492 (IFC_FIR_OP_CMD2 << IFC_NAND_FIR0_OP1_SHIFT) |
493 (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP2_SHIFT) |
494 (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP3_SHIFT) |
495 (IFC_FIR_OP_WBCD << IFC_NAND_FIR0_OP4_SHIFT));
496 ifc_out32(&ifc->ifc_nand.nand_fir1,
497 (IFC_FIR_OP_CMD1 << IFC_NAND_FIR1_OP5_SHIFT) |
498 (IFC_FIR_OP_CW3 << IFC_NAND_FIR1_OP6_SHIFT) |
499 (IFC_FIR_OP_RDSTAT <<
Prabhakar Kushwaha18e6bde2013-10-03 11:35:35 +0530500 IFC_NAND_FIR1_OP7_SHIFT) |
Prabhakar Kushwaha62908c22014-01-18 12:28:30 +0530501 (IFC_FIR_OP_NOP << IFC_NAND_FIR1_OP8_SHIFT));
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530502
Prabhakar Kushwaha0ed5e772012-01-20 18:39:05 +0530503 if (column >= mtd->writesize)
504 nand_fcr0 |=
505 NAND_CMD_READOOB << IFC_NAND_FCR0_CMD0_SHIFT;
506 else
507 nand_fcr0 |=
508 NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT;
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530509 }
510
Prabhakar Kushwaha0ed5e772012-01-20 18:39:05 +0530511 if (column >= mtd->writesize) {
512 /* OOB area --> READOOB */
513 column -= mtd->writesize;
514 ctrl->oob = 1;
515 }
Prabhakar Kushwaha62908c22014-01-18 12:28:30 +0530516 ifc_out32(&ifc->ifc_nand.nand_fcr0, nand_fcr0);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530517 set_addr(mtd, column, page_addr, ctrl->oob);
518 return;
519 }
520
521 /* PAGEPROG reuses all of the setup from SEQIN and adds the length */
522 case NAND_CMD_PAGEPROG:
523 if (ctrl->oob)
Prabhakar Kushwaha62908c22014-01-18 12:28:30 +0530524 ifc_out32(&ifc->ifc_nand.nand_fbcr,
525 ctrl->index - ctrl->column);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530526 else
Prabhakar Kushwaha62908c22014-01-18 12:28:30 +0530527 ifc_out32(&ifc->ifc_nand.nand_fbcr, 0);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530528
529 fsl_ifc_run_command(mtd);
530 return;
531
532 case NAND_CMD_STATUS:
Prabhakar Kushwaha62908c22014-01-18 12:28:30 +0530533 ifc_out32(&ifc->ifc_nand.nand_fir0,
534 (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
535 (IFC_FIR_OP_RB << IFC_NAND_FIR0_OP1_SHIFT));
536 ifc_out32(&ifc->ifc_nand.nand_fcr0,
537 NAND_CMD_STATUS << IFC_NAND_FCR0_CMD0_SHIFT);
538 ifc_out32(&ifc->ifc_nand.nand_fbcr, 1);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530539 set_addr(mtd, 0, 0, 0);
540 ctrl->read_bytes = 1;
541
542 fsl_ifc_run_command(mtd);
543
Scott Wood3ea94ed2015-06-26 19:03:26 -0500544 /*
545 * The chip always seems to report that it is
546 * write-protected, even when it is not.
547 */
548 if (chip->options & NAND_BUSWIDTH_16)
549 ifc_out16(ctrl->addr,
550 ifc_in16(ctrl->addr) | NAND_STATUS_WP);
551 else
552 out_8(ctrl->addr, in_8(ctrl->addr) | NAND_STATUS_WP);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530553 return;
554
555 case NAND_CMD_RESET:
Prabhakar Kushwaha62908c22014-01-18 12:28:30 +0530556 ifc_out32(&ifc->ifc_nand.nand_fir0,
557 IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT);
558 ifc_out32(&ifc->ifc_nand.nand_fcr0,
559 NAND_CMD_RESET << IFC_NAND_FCR0_CMD0_SHIFT);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530560 fsl_ifc_run_command(mtd);
561 return;
562
563 default:
564 printf("%s: error, unsupported command 0x%x.\n",
565 __func__, command);
566 }
567}
568
569/*
570 * Write buf to the IFC NAND Controller Data Buffer
571 */
572static void fsl_ifc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
573{
Scott Wood17fed142016-05-30 13:57:56 -0500574 struct nand_chip *chip = mtd_to_nand(mtd);
575 struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530576 struct fsl_ifc_ctrl *ctrl = priv->ctrl;
577 unsigned int bufsize = mtd->writesize + mtd->oobsize;
578
579 if (len <= 0) {
580 printf("%s of %d bytes", __func__, len);
581 ctrl->status = 0;
582 return;
583 }
584
585 if ((unsigned int)len > bufsize - ctrl->index) {
586 printf("%s beyond end of buffer "
587 "(%d requested, %u available)\n",
588 __func__, len, bufsize - ctrl->index);
589 len = bufsize - ctrl->index;
590 }
591
Scott Wood3ea94ed2015-06-26 19:03:26 -0500592 memcpy_toio(ctrl->addr + ctrl->index, buf, len);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530593 ctrl->index += len;
594}
595
596/*
597 * read a byte from either the IFC hardware buffer if it has any data left
598 * otherwise issue a command to read a single byte.
599 */
600static u8 fsl_ifc_read_byte(struct mtd_info *mtd)
601{
Scott Wood17fed142016-05-30 13:57:56 -0500602 struct nand_chip *chip = mtd_to_nand(mtd);
603 struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530604 struct fsl_ifc_ctrl *ctrl = priv->ctrl;
Scott Wood3ea94ed2015-06-26 19:03:26 -0500605 unsigned int offset;
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530606
Scott Wood3ea94ed2015-06-26 19:03:26 -0500607 /*
608 * If there are still bytes in the IFC buffer, then use the
609 * next byte.
610 */
611 if (ctrl->index < ctrl->read_bytes) {
612 offset = ctrl->index++;
613 return in_8(ctrl->addr + offset);
614 }
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530615
616 printf("%s beyond end of buffer\n", __func__);
617 return ERR_BYTE;
618}
619
620/*
621 * Read two bytes from the IFC hardware buffer
622 * read function for 16-bit buswith
623 */
624static uint8_t fsl_ifc_read_byte16(struct mtd_info *mtd)
625{
Scott Wood17fed142016-05-30 13:57:56 -0500626 struct nand_chip *chip = mtd_to_nand(mtd);
627 struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530628 struct fsl_ifc_ctrl *ctrl = priv->ctrl;
629 uint16_t data;
630
631 /*
632 * If there are still bytes in the IFC buffer, then use the
633 * next byte.
634 */
635 if (ctrl->index < ctrl->read_bytes) {
Scott Wood3ea94ed2015-06-26 19:03:26 -0500636 data = ifc_in16(ctrl->addr + ctrl->index);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530637 ctrl->index += 2;
638 return (uint8_t)data;
639 }
640
641 printf("%s beyond end of buffer\n", __func__);
642 return ERR_BYTE;
643}
644
645/*
646 * Read from the IFC Controller Data Buffer
647 */
648static void fsl_ifc_read_buf(struct mtd_info *mtd, u8 *buf, int len)
649{
Scott Wood17fed142016-05-30 13:57:56 -0500650 struct nand_chip *chip = mtd_to_nand(mtd);
651 struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530652 struct fsl_ifc_ctrl *ctrl = priv->ctrl;
653 int avail;
654
655 if (len < 0)
656 return;
657
658 avail = min((unsigned int)len, ctrl->read_bytes - ctrl->index);
Scott Wood3ea94ed2015-06-26 19:03:26 -0500659 memcpy_fromio(buf, ctrl->addr + ctrl->index, avail);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530660 ctrl->index += avail;
661
662 if (len > avail)
663 printf("%s beyond end of buffer "
664 "(%d requested, %d available)\n",
665 __func__, len, avail);
666}
667
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530668/* This function is called after Program and Erase Operations to
669 * check for success or failure.
670 */
671static int fsl_ifc_wait(struct mtd_info *mtd, struct nand_chip *chip)
672{
Scott Wood17fed142016-05-30 13:57:56 -0500673 struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530674 struct fsl_ifc_ctrl *ctrl = priv->ctrl;
Jaiprakash Singhdd888062015-03-20 19:28:27 -0700675 struct fsl_ifc_runtime *ifc = ctrl->regs.rregs;
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530676 u32 nand_fsr;
Jagdish Gediya997f04a2018-05-02 01:20:57 +0530677 int status;
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530678
679 if (ctrl->status != IFC_NAND_EVTER_STAT_OPC)
680 return NAND_STATUS_FAIL;
681
682 /* Use READ_STATUS command, but wait for the device to be ready */
Prabhakar Kushwaha62908c22014-01-18 12:28:30 +0530683 ifc_out32(&ifc->ifc_nand.nand_fir0,
684 (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
685 (IFC_FIR_OP_RDSTAT << IFC_NAND_FIR0_OP1_SHIFT));
686 ifc_out32(&ifc->ifc_nand.nand_fcr0, NAND_CMD_STATUS <<
687 IFC_NAND_FCR0_CMD0_SHIFT);
688 ifc_out32(&ifc->ifc_nand.nand_fbcr, 1);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530689 set_addr(mtd, 0, 0, 0);
690 ctrl->read_bytes = 1;
691
692 fsl_ifc_run_command(mtd);
693
694 if (ctrl->status != IFC_NAND_EVTER_STAT_OPC)
695 return NAND_STATUS_FAIL;
696
Prabhakar Kushwaha62908c22014-01-18 12:28:30 +0530697 nand_fsr = ifc_in32(&ifc->ifc_nand.nand_fsr);
Jagdish Gediya997f04a2018-05-02 01:20:57 +0530698 status = nand_fsr >> 24;
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530699
700 /* Chip sometimes reporting write protect even when it's not */
Jagdish Gediya997f04a2018-05-02 01:20:57 +0530701 return status | NAND_STATUS_WP;
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530702}
703
Darwin Dingel3dae7e62018-08-02 10:02:45 +0200704/*
705 * The controller does not check for bitflips in erased pages,
706 * therefore software must check instead.
707 */
708static int
709check_erased_page(struct nand_chip *chip, u8 *buf, struct mtd_info *mtd)
710{
711 u8 *ecc = chip->oob_poi;
712 const int ecc_size = chip->ecc.bytes;
713 const int pkt_size = chip->ecc.size;
714 int i, res, bitflips;
715
716 /* IFC starts ecc bytes at offset 8 in the spare area. */
717 ecc += 8;
718 bitflips = 0;
719 for (i = 0; i < chip->ecc.steps; i++) {
720 res = nand_check_erased_ecc_chunk(buf, pkt_size, ecc, ecc_size,
721 NULL, 0, chip->ecc.strength);
722
723 if (res < 0) {
724 printf("fsl-ifc: NAND Flash ECC Uncorrectable Error\n");
725 mtd->ecc_stats.failed++;
726 } else if (res > 0) {
727 mtd->ecc_stats.corrected += res;
728 }
729 bitflips = max(res, bitflips);
730 buf += pkt_size;
731 ecc += ecc_size;
732 }
733
734 return bitflips;
735}
736
Sergey Lapin3a38a552013-01-14 03:46:50 +0000737static int fsl_ifc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
738 uint8_t *buf, int oob_required, int page)
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530739{
Scott Wood17fed142016-05-30 13:57:56 -0500740 struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530741 struct fsl_ifc_ctrl *ctrl = priv->ctrl;
742
743 fsl_ifc_read_buf(mtd, buf, mtd->writesize);
744 fsl_ifc_read_buf(mtd, chip->oob_poi, mtd->oobsize);
745
Darwin Dingel3dae7e62018-08-02 10:02:45 +0200746 if (ctrl->status & IFC_NAND_EVTER_STAT_ECCER)
747 return check_erased_page(chip, buf, mtd);
748
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530749 if (ctrl->status != IFC_NAND_EVTER_STAT_OPC)
750 mtd->ecc_stats.failed++;
751
752 return 0;
753}
754
755/* ECC will be calculated automatically, and errors will be detected in
756 * waitfunc.
757 */
Sergey Lapin3a38a552013-01-14 03:46:50 +0000758static int fsl_ifc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
Scott Wood46e13102016-05-30 13:57:57 -0500759 const uint8_t *buf, int oob_required, int page)
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530760{
761 fsl_ifc_write_buf(mtd, buf, mtd->writesize);
762 fsl_ifc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
Sergey Lapin3a38a552013-01-14 03:46:50 +0000763
764 return 0;
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530765}
766
767static void fsl_ifc_ctrl_init(void)
768{
Jaiprakash Singhdd888062015-03-20 19:28:27 -0700769 uint32_t ver = 0;
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530770 ifc_ctrl = kzalloc(sizeof(*ifc_ctrl), GFP_KERNEL);
771 if (!ifc_ctrl)
772 return;
773
Jaiprakash Singhdd888062015-03-20 19:28:27 -0700774 ifc_ctrl->regs.gregs = IFC_FCM_BASE_ADDR;
775
776 ver = ifc_in32(&ifc_ctrl->regs.gregs->ifc_rev);
777 if (ver >= FSL_IFC_V2_0_0)
778 ifc_ctrl->regs.rregs =
Tom Rini6a5dccc2022-11-16 13:10:41 -0500779 (void *)CFG_SYS_IFC_ADDR + IFC_RREGS_64KOFFSET;
Jaiprakash Singhdd888062015-03-20 19:28:27 -0700780 else
781 ifc_ctrl->regs.rregs =
Tom Rini6a5dccc2022-11-16 13:10:41 -0500782 (void *)CFG_SYS_IFC_ADDR + IFC_RREGS_4KOFFSET;
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530783
784 /* clear event registers */
Jaiprakash Singhdd888062015-03-20 19:28:27 -0700785 ifc_out32(&ifc_ctrl->regs.rregs->ifc_nand.nand_evter_stat, ~0U);
786 ifc_out32(&ifc_ctrl->regs.rregs->ifc_nand.pgrdcmpl_evt_stat, ~0U);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530787
788 /* Enable error and event for any detected errors */
Jaiprakash Singhdd888062015-03-20 19:28:27 -0700789 ifc_out32(&ifc_ctrl->regs.rregs->ifc_nand.nand_evter_en,
Prabhakar Kushwaha62908c22014-01-18 12:28:30 +0530790 IFC_NAND_EVTER_EN_OPC_EN |
791 IFC_NAND_EVTER_EN_PGRDCMPL_EN |
792 IFC_NAND_EVTER_EN_FTOER_EN |
793 IFC_NAND_EVTER_EN_WPER_EN);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530794
Jaiprakash Singhdd888062015-03-20 19:28:27 -0700795 ifc_out32(&ifc_ctrl->regs.rregs->ifc_nand.ncfgr, 0x0);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530796}
797
798static void fsl_ifc_select_chip(struct mtd_info *mtd, int chip)
799{
800}
801
Kurt Kanzenbach1f161f82017-10-20 11:44:25 +0200802static int fsl_ifc_sram_init(struct fsl_ifc_mtd *priv, uint32_t ver)
Prabhakar Kushwahadccbf352012-09-12 22:26:05 +0000803{
Jaiprakash Singhdd888062015-03-20 19:28:27 -0700804 struct fsl_ifc_runtime *ifc = ifc_ctrl->regs.rregs;
Prabhakar Kushwahadccbf352012-09-12 22:26:05 +0000805 uint32_t cs = 0, csor = 0, csor_8k = 0, csor_ext = 0;
Prabhakar Kushwaha82efc812014-06-12 12:14:00 +0530806 uint32_t ncfgr = 0;
Prabhakar Kushwahad7550e12014-09-23 09:57:47 +0530807 u32 timeo = (CONFIG_SYS_HZ * 10) / 1000;
808 u32 time_start;
Prabhakar Kushwahadccbf352012-09-12 22:26:05 +0000809
Prabhakar Kushwaha82efc812014-06-12 12:14:00 +0530810 if (ver > FSL_IFC_V1_1_0) {
811 ncfgr = ifc_in32(&ifc->ifc_nand.ncfgr);
812 ifc_out32(&ifc->ifc_nand.ncfgr, ncfgr | IFC_NAND_SRAM_INIT_EN);
813
814 /* wait for SRAM_INIT bit to be clear or timeout */
Prabhakar Kushwahad7550e12014-09-23 09:57:47 +0530815 time_start = get_timer(0);
816 while (get_timer(time_start) < timeo) {
Prabhakar Kushwaha82efc812014-06-12 12:14:00 +0530817 ifc_ctrl->status =
818 ifc_in32(&ifc->ifc_nand.nand_evter_stat);
819
820 if (!(ifc_ctrl->status & IFC_NAND_SRAM_INIT_EN))
821 return 0;
822 }
823 printf("fsl-ifc: Failed to Initialise SRAM\n");
824 return 1;
825 }
826
Kurt Kanzenbach1f161f82017-10-20 11:44:25 +0200827 cs = priv->bank;
Prabhakar Kushwahadccbf352012-09-12 22:26:05 +0000828
829 /* Save CSOR and CSOR_ext */
Jaiprakash Singhdd888062015-03-20 19:28:27 -0700830 csor = ifc_in32(&ifc_ctrl->regs.gregs->csor_cs[cs].csor);
831 csor_ext = ifc_in32(&ifc_ctrl->regs.gregs->csor_cs[cs].csor_ext);
Prabhakar Kushwahadccbf352012-09-12 22:26:05 +0000832
833 /* chage PageSize 8K and SpareSize 1K*/
834 csor_8k = (csor & ~(CSOR_NAND_PGS_MASK)) | 0x0018C000;
Jaiprakash Singhdd888062015-03-20 19:28:27 -0700835 ifc_out32(&ifc_ctrl->regs.gregs->csor_cs[cs].csor, csor_8k);
836 ifc_out32(&ifc_ctrl->regs.gregs->csor_cs[cs].csor_ext, 0x0000400);
Prabhakar Kushwahadccbf352012-09-12 22:26:05 +0000837
838 /* READID */
Prabhakar Kushwaha62908c22014-01-18 12:28:30 +0530839 ifc_out32(&ifc->ifc_nand.nand_fir0,
840 (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
841 (IFC_FIR_OP_UA << IFC_NAND_FIR0_OP1_SHIFT) |
842 (IFC_FIR_OP_RB << IFC_NAND_FIR0_OP2_SHIFT));
843 ifc_out32(&ifc->ifc_nand.nand_fcr0,
844 NAND_CMD_READID << IFC_NAND_FCR0_CMD0_SHIFT);
845 ifc_out32(&ifc->ifc_nand.row3, 0x0);
Prabhakar Kushwahadccbf352012-09-12 22:26:05 +0000846
Prabhakar Kushwaha62908c22014-01-18 12:28:30 +0530847 ifc_out32(&ifc->ifc_nand.nand_fbcr, 0x0);
Prabhakar Kushwahadccbf352012-09-12 22:26:05 +0000848
849 /* Program ROW0/COL0 */
Prabhakar Kushwaha62908c22014-01-18 12:28:30 +0530850 ifc_out32(&ifc->ifc_nand.row0, 0x0);
851 ifc_out32(&ifc->ifc_nand.col0, 0x0);
Prabhakar Kushwahadccbf352012-09-12 22:26:05 +0000852
853 /* set the chip select for NAND Transaction */
Kurt Kanzenbach1f161f82017-10-20 11:44:25 +0200854 ifc_out32(&ifc->ifc_nand.nand_csel, priv->bank << IFC_NAND_CSEL_SHIFT);
Prabhakar Kushwahadccbf352012-09-12 22:26:05 +0000855
856 /* start read seq */
Prabhakar Kushwaha62908c22014-01-18 12:28:30 +0530857 ifc_out32(&ifc->ifc_nand.nandseq_strt, IFC_NAND_SEQ_STRT_FIR_STRT);
Prabhakar Kushwahadccbf352012-09-12 22:26:05 +0000858
Prabhakar Kushwahad7550e12014-09-23 09:57:47 +0530859 time_start = get_timer(0);
Prabhakar Kushwahadccbf352012-09-12 22:26:05 +0000860
Prabhakar Kushwahad7550e12014-09-23 09:57:47 +0530861 while (get_timer(time_start) < timeo) {
Prabhakar Kushwaha62908c22014-01-18 12:28:30 +0530862 ifc_ctrl->status = ifc_in32(&ifc->ifc_nand.nand_evter_stat);
Prabhakar Kushwahadccbf352012-09-12 22:26:05 +0000863
864 if (ifc_ctrl->status & IFC_NAND_EVTER_STAT_OPC)
865 break;
866 }
867
Prabhakar Kushwaha82efc812014-06-12 12:14:00 +0530868 if (ifc_ctrl->status != IFC_NAND_EVTER_STAT_OPC) {
869 printf("fsl-ifc: Failed to Initialise SRAM\n");
870 return 1;
871 }
872
Prabhakar Kushwaha62908c22014-01-18 12:28:30 +0530873 ifc_out32(&ifc->ifc_nand.nand_evter_stat, ifc_ctrl->status);
Prabhakar Kushwahadccbf352012-09-12 22:26:05 +0000874
875 /* Restore CSOR and CSOR_ext */
Jaiprakash Singhdd888062015-03-20 19:28:27 -0700876 ifc_out32(&ifc_ctrl->regs.gregs->csor_cs[cs].csor, csor);
877 ifc_out32(&ifc_ctrl->regs.gregs->csor_cs[cs].csor_ext, csor_ext);
Prabhakar Kushwaha82efc812014-06-12 12:14:00 +0530878
879 return 0;
Prabhakar Kushwahadccbf352012-09-12 22:26:05 +0000880}
881
Prabhakar Kushwaha895d0392013-04-04 18:44:06 +0000882static int fsl_ifc_chip_init(int devnum, u8 *addr)
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530883{
Scott Wood2c1b7e12016-05-30 13:57:55 -0500884 struct mtd_info *mtd;
Prabhakar Kushwaha895d0392013-04-04 18:44:06 +0000885 struct nand_chip *nand;
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530886 struct fsl_ifc_mtd *priv;
887 struct nand_ecclayout *layout;
Jaiprakash Singhdd888062015-03-20 19:28:27 -0700888 struct fsl_ifc_fcm *gregs = NULL;
Prabhakar Kushwahadccbf352012-09-12 22:26:05 +0000889 uint32_t cspr = 0, csor = 0, ver = 0;
Prabhakar Kushwaha82efc812014-06-12 12:14:00 +0530890 int ret = 0;
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530891
892 if (!ifc_ctrl) {
893 fsl_ifc_ctrl_init();
894 if (!ifc_ctrl)
895 return -1;
896 }
897
898 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
899 if (!priv)
900 return -ENOMEM;
901
902 priv->ctrl = ifc_ctrl;
Prabhakar Kushwaha895d0392013-04-04 18:44:06 +0000903 priv->vbase = addr;
Jaiprakash Singhdd888062015-03-20 19:28:27 -0700904 gregs = ifc_ctrl->regs.gregs;
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530905
906 /* Find which chip select it is connected to.
907 */
908 for (priv->bank = 0; priv->bank < MAX_BANKS; priv->bank++) {
Prabhakar Kushwaha895d0392013-04-04 18:44:06 +0000909 phys_addr_t phys_addr = virt_to_phys(addr);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530910
Jaiprakash Singhdd888062015-03-20 19:28:27 -0700911 cspr = ifc_in32(&gregs->cspr_cs[priv->bank].cspr);
912 csor = ifc_in32(&gregs->csor_cs[priv->bank].csor);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530913
914 if ((cspr & CSPR_V) && (cspr & CSPR_MSEL) == CSPR_MSEL_NAND &&
Kurt Kanzenbach1f161f82017-10-20 11:44:25 +0200915 (cspr & CSPR_BA) == CSPR_PHYS_ADDR(phys_addr))
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530916 break;
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530917 }
918
919 if (priv->bank >= MAX_BANKS) {
920 printf("%s: address did not match any "
921 "chip selects\n", __func__);
Prabhakar Kushwahaae25e882012-04-10 22:48:27 +0000922 kfree(priv);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530923 return -ENODEV;
924 }
925
Prabhakar Kushwaha895d0392013-04-04 18:44:06 +0000926 nand = &priv->chip;
Scott Wood17fed142016-05-30 13:57:56 -0500927 mtd = nand_to_mtd(nand);
Prabhakar Kushwaha895d0392013-04-04 18:44:06 +0000928
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530929 ifc_ctrl->chips[priv->bank] = priv;
930
931 /* fill in nand_chip structure */
932 /* set up function call table */
933
934 nand->write_buf = fsl_ifc_write_buf;
935 nand->read_buf = fsl_ifc_read_buf;
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530936 nand->select_chip = fsl_ifc_select_chip;
937 nand->cmdfunc = fsl_ifc_cmdfunc;
938 nand->waitfunc = fsl_ifc_wait;
939
940 /* set up nand options */
941 nand->bbt_td = &bbt_main_descr;
942 nand->bbt_md = &bbt_mirror_descr;
943
944 /* set up nand options */
Sergey Lapin3a38a552013-01-14 03:46:50 +0000945 nand->options = NAND_NO_SUBPAGE_WRITE;
946 nand->bbt_options = NAND_BBT_USE_FLASH;
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530947
948 if (cspr & CSPR_PORT_SIZE_16) {
949 nand->read_byte = fsl_ifc_read_byte16;
950 nand->options |= NAND_BUSWIDTH_16;
951 } else {
952 nand->read_byte = fsl_ifc_read_byte;
953 }
954
955 nand->controller = &ifc_ctrl->controller;
Scott Wood17fed142016-05-30 13:57:56 -0500956 nand_set_controller_data(nand, priv);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530957
958 nand->ecc.read_page = fsl_ifc_read_page;
959 nand->ecc.write_page = fsl_ifc_write_page;
960
961 /* Hardware generates ECC per 512 Bytes */
962 nand->ecc.size = 512;
963 nand->ecc.bytes = 8;
964
965 switch (csor & CSOR_NAND_PGS_MASK) {
966 case CSOR_NAND_PGS_512:
967 if (nand->options & NAND_BUSWIDTH_16) {
968 layout = &oob_512_16bit_ecc4;
969 } else {
970 layout = &oob_512_8bit_ecc4;
971
972 /* Avoid conflict with bad block marker */
973 bbt_main_descr.offs = 0;
974 bbt_mirror_descr.offs = 0;
975 }
976
Sergey Lapin3a38a552013-01-14 03:46:50 +0000977 nand->ecc.strength = 4;
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530978 priv->bufnum_mask = 15;
979 break;
980
981 case CSOR_NAND_PGS_2K:
982 layout = &oob_2048_ecc4;
Sergey Lapin3a38a552013-01-14 03:46:50 +0000983 nand->ecc.strength = 4;
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530984 priv->bufnum_mask = 3;
985 break;
986
987 case CSOR_NAND_PGS_4K:
988 if ((csor & CSOR_NAND_ECC_MODE_MASK) ==
989 CSOR_NAND_ECC_MODE_4) {
990 layout = &oob_4096_ecc4;
Sergey Lapin3a38a552013-01-14 03:46:50 +0000991 nand->ecc.strength = 4;
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530992 } else {
993 layout = &oob_4096_ecc8;
Sergey Lapin3a38a552013-01-14 03:46:50 +0000994 nand->ecc.strength = 8;
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530995 nand->ecc.bytes = 16;
996 }
997
998 priv->bufnum_mask = 1;
999 break;
1000
Prabhakar Kushwahaa3aaf1d2013-10-04 10:05:36 +05301001 case CSOR_NAND_PGS_8K:
1002 if ((csor & CSOR_NAND_ECC_MODE_MASK) ==
1003 CSOR_NAND_ECC_MODE_4) {
1004 layout = &oob_8192_ecc4;
1005 nand->ecc.strength = 4;
1006 } else {
1007 layout = &oob_8192_ecc8;
1008 nand->ecc.strength = 8;
1009 nand->ecc.bytes = 16;
1010 }
1011
1012 priv->bufnum_mask = 0;
1013 break;
1014
1015
Dipen Dudhat9eae0832011-03-22 09:27:39 +05301016 default:
1017 printf("ifc nand: bad csor %#x: bad page size\n", csor);
1018 return -ENODEV;
1019 }
1020
1021 /* Must also set CSOR_NAND_ECC_ENC_EN if DEC_EN set */
1022 if (csor & CSOR_NAND_ECC_DEC_EN) {
1023 nand->ecc.mode = NAND_ECC_HW;
1024 nand->ecc.layout = layout;
1025 } else {
1026 nand->ecc.mode = NAND_ECC_SOFT;
1027 }
1028
Jaiprakash Singhdd888062015-03-20 19:28:27 -07001029 ver = ifc_in32(&gregs->ifc_rev);
Prabhakar Kushwaha82efc812014-06-12 12:14:00 +05301030 if (ver >= FSL_IFC_V1_1_0)
Kurt Kanzenbach1f161f82017-10-20 11:44:25 +02001031 ret = fsl_ifc_sram_init(priv, ver);
Prabhakar Kushwaha82efc812014-06-12 12:14:00 +05301032 if (ret)
1033 return ret;
Prabhakar Kushwahadccbf352012-09-12 22:26:05 +00001034
Prabhakar Kushwaha5c23a822014-06-14 08:48:19 +05301035 if (ver >= FSL_IFC_V2_0_0)
1036 priv->bufnum_mask = (priv->bufnum_mask * 2) + 1;
1037
Prabhakar Kushwaha895d0392013-04-04 18:44:06 +00001038 ret = nand_scan_ident(mtd, 1, NULL);
1039 if (ret)
1040 return ret;
1041
1042 ret = nand_scan_tail(mtd);
1043 if (ret)
1044 return ret;
1045
Scott Wood2c1b7e12016-05-30 13:57:55 -05001046 ret = nand_register(devnum, mtd);
Prabhakar Kushwaha895d0392013-04-04 18:44:06 +00001047 if (ret)
1048 return ret;
Dipen Dudhat9eae0832011-03-22 09:27:39 +05301049 return 0;
1050}
Prabhakar Kushwaha895d0392013-04-04 18:44:06 +00001051
Tom Rinib4213492022-11-12 17:36:51 -05001052#ifndef CFG_SYS_NAND_BASE_LIST
1053#define CFG_SYS_NAND_BASE_LIST { CFG_SYS_NAND_BASE }
Prabhakar Kushwaha895d0392013-04-04 18:44:06 +00001054#endif
1055
1056static unsigned long base_address[CONFIG_SYS_MAX_NAND_DEVICE] =
Tom Rinib4213492022-11-12 17:36:51 -05001057 CFG_SYS_NAND_BASE_LIST;
Prabhakar Kushwaha895d0392013-04-04 18:44:06 +00001058
1059void board_nand_init(void)
1060{
1061 int i;
1062
1063 for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++)
1064 fsl_ifc_chip_init(i, (u8 *)base_address[i]);
1065}