blob: d1165f7d6b5e40b17f54c5232ce5109b80094b17 [file] [log] [blame]
Dipen Dudhat9eae0832011-03-22 09:27:39 +05301/* Integrated Flash Controller NAND Machine Driver
2 *
Prabhakar Kushwahacdd045d2012-01-20 18:38:14 +05303 * Copyright (c) 2012 Freescale Semiconductor, Inc
Dipen Dudhat9eae0832011-03-22 09:27:39 +05304 *
5 * Authors: Dipen Dudhat <Dipen.Dudhat@freescale.com>
6 *
Wolfgang Denkd79de1d2013-07-08 09:37:19 +02007 * SPDX-License-Identifier: GPL-2.0+
Dipen Dudhat9eae0832011-03-22 09:27:39 +05308 */
9
10#include <common.h>
11#include <malloc.h>
Prabhakar Kushwaha895d0392013-04-04 18:44:06 +000012#include <nand.h>
Dipen Dudhat9eae0832011-03-22 09:27:39 +053013
14#include <linux/mtd/mtd.h>
Masahiro Yamada2b7a8732017-11-30 13:45:24 +090015#include <linux/mtd/rawnand.h>
Dipen Dudhat9eae0832011-03-22 09:27:39 +053016#include <linux/mtd/nand_ecc.h>
17
18#include <asm/io.h>
Masahiro Yamada56a931c2016-09-21 11:28:55 +090019#include <linux/errno.h>
York Sun37562f62013-10-22 12:39:02 -070020#include <fsl_ifc.h>
Dipen Dudhat9eae0832011-03-22 09:27:39 +053021
Prabhakar Kushwahaa8759642014-06-12 09:13:08 +053022#ifndef CONFIG_SYS_FSL_IFC_BANK_COUNT
23#define CONFIG_SYS_FSL_IFC_BANK_COUNT 4
24#endif
25
Prabhakar Kushwahaa8759642014-06-12 09:13:08 +053026#define MAX_BANKS CONFIG_SYS_FSL_IFC_BANK_COUNT
Dipen Dudhat9eae0832011-03-22 09:27:39 +053027#define ERR_BYTE 0xFF /* Value returned for read bytes
28 when read failed */
Dipen Dudhat9eae0832011-03-22 09:27:39 +053029
30struct fsl_ifc_ctrl;
31
32/* mtd information per set */
33struct fsl_ifc_mtd {
Dipen Dudhat9eae0832011-03-22 09:27:39 +053034 struct nand_chip chip;
35 struct fsl_ifc_ctrl *ctrl;
36
37 struct device *dev;
38 int bank; /* Chip select bank number */
39 unsigned int bufnum_mask; /* bufnum = page & bufnum_mask */
40 u8 __iomem *vbase; /* Chip select base virtual address */
41};
42
43/* overview of the fsl ifc controller */
44struct fsl_ifc_ctrl {
45 struct nand_hw_control controller;
46 struct fsl_ifc_mtd *chips[MAX_BANKS];
47
48 /* device info */
Jaiprakash Singhdd888062015-03-20 19:28:27 -070049 struct fsl_ifc regs;
Scott Wood3ea94ed2015-06-26 19:03:26 -050050 void __iomem *addr; /* Address of assigned IFC buffer */
Dipen Dudhat9eae0832011-03-22 09:27:39 +053051 unsigned int page; /* Last page written to / read from */
52 unsigned int read_bytes; /* Number of bytes read during command */
53 unsigned int column; /* Saved column from SEQIN */
54 unsigned int index; /* Pointer to next byte to 'read' */
55 unsigned int status; /* status read from NEESR after last op */
56 unsigned int oob; /* Non zero if operating on OOB data */
57 unsigned int eccread; /* Non zero for a full-page ECC read */
58};
59
60static struct fsl_ifc_ctrl *ifc_ctrl;
61
62/* 512-byte page with 4-bit ECC, 8-bit */
63static struct nand_ecclayout oob_512_8bit_ecc4 = {
64 .eccbytes = 8,
65 .eccpos = {8, 9, 10, 11, 12, 13, 14, 15},
66 .oobfree = { {0, 5}, {6, 2} },
67};
68
69/* 512-byte page with 4-bit ECC, 16-bit */
70static struct nand_ecclayout oob_512_16bit_ecc4 = {
71 .eccbytes = 8,
72 .eccpos = {8, 9, 10, 11, 12, 13, 14, 15},
73 .oobfree = { {2, 6}, },
74};
75
76/* 2048-byte page size with 4-bit ECC */
77static struct nand_ecclayout oob_2048_ecc4 = {
78 .eccbytes = 32,
79 .eccpos = {
80 8, 9, 10, 11, 12, 13, 14, 15,
81 16, 17, 18, 19, 20, 21, 22, 23,
82 24, 25, 26, 27, 28, 29, 30, 31,
83 32, 33, 34, 35, 36, 37, 38, 39,
84 },
85 .oobfree = { {2, 6}, {40, 24} },
86};
87
88/* 4096-byte page size with 4-bit ECC */
89static struct nand_ecclayout oob_4096_ecc4 = {
90 .eccbytes = 64,
91 .eccpos = {
92 8, 9, 10, 11, 12, 13, 14, 15,
93 16, 17, 18, 19, 20, 21, 22, 23,
94 24, 25, 26, 27, 28, 29, 30, 31,
95 32, 33, 34, 35, 36, 37, 38, 39,
96 40, 41, 42, 43, 44, 45, 46, 47,
97 48, 49, 50, 51, 52, 53, 54, 55,
98 56, 57, 58, 59, 60, 61, 62, 63,
99 64, 65, 66, 67, 68, 69, 70, 71,
100 },
101 .oobfree = { {2, 6}, {72, 56} },
102};
103
104/* 4096-byte page size with 8-bit ECC -- requires 218-byte OOB */
105static struct nand_ecclayout oob_4096_ecc8 = {
106 .eccbytes = 128,
107 .eccpos = {
108 8, 9, 10, 11, 12, 13, 14, 15,
109 16, 17, 18, 19, 20, 21, 22, 23,
110 24, 25, 26, 27, 28, 29, 30, 31,
111 32, 33, 34, 35, 36, 37, 38, 39,
112 40, 41, 42, 43, 44, 45, 46, 47,
113 48, 49, 50, 51, 52, 53, 54, 55,
114 56, 57, 58, 59, 60, 61, 62, 63,
115 64, 65, 66, 67, 68, 69, 70, 71,
116 72, 73, 74, 75, 76, 77, 78, 79,
117 80, 81, 82, 83, 84, 85, 86, 87,
118 88, 89, 90, 91, 92, 93, 94, 95,
119 96, 97, 98, 99, 100, 101, 102, 103,
120 104, 105, 106, 107, 108, 109, 110, 111,
121 112, 113, 114, 115, 116, 117, 118, 119,
122 120, 121, 122, 123, 124, 125, 126, 127,
123 128, 129, 130, 131, 132, 133, 134, 135,
124 },
125 .oobfree = { {2, 6}, {136, 82} },
126};
127
Prabhakar Kushwahaa3aaf1d2013-10-04 10:05:36 +0530128/* 8192-byte page size with 4-bit ECC */
129static struct nand_ecclayout oob_8192_ecc4 = {
130 .eccbytes = 128,
131 .eccpos = {
132 8, 9, 10, 11, 12, 13, 14, 15,
133 16, 17, 18, 19, 20, 21, 22, 23,
134 24, 25, 26, 27, 28, 29, 30, 31,
135 32, 33, 34, 35, 36, 37, 38, 39,
136 40, 41, 42, 43, 44, 45, 46, 47,
137 48, 49, 50, 51, 52, 53, 54, 55,
138 56, 57, 58, 59, 60, 61, 62, 63,
139 64, 65, 66, 67, 68, 69, 70, 71,
140 72, 73, 74, 75, 76, 77, 78, 79,
141 80, 81, 82, 83, 84, 85, 86, 87,
142 88, 89, 90, 91, 92, 93, 94, 95,
143 96, 97, 98, 99, 100, 101, 102, 103,
144 104, 105, 106, 107, 108, 109, 110, 111,
145 112, 113, 114, 115, 116, 117, 118, 119,
146 120, 121, 122, 123, 124, 125, 126, 127,
147 128, 129, 130, 131, 132, 133, 134, 135,
148 },
149 .oobfree = { {2, 6}, {136, 208} },
150};
151
152/* 8192-byte page size with 8-bit ECC -- requires 218-byte OOB */
153static struct nand_ecclayout oob_8192_ecc8 = {
154 .eccbytes = 256,
155 .eccpos = {
156 8, 9, 10, 11, 12, 13, 14, 15,
157 16, 17, 18, 19, 20, 21, 22, 23,
158 24, 25, 26, 27, 28, 29, 30, 31,
159 32, 33, 34, 35, 36, 37, 38, 39,
160 40, 41, 42, 43, 44, 45, 46, 47,
161 48, 49, 50, 51, 52, 53, 54, 55,
162 56, 57, 58, 59, 60, 61, 62, 63,
163 64, 65, 66, 67, 68, 69, 70, 71,
164 72, 73, 74, 75, 76, 77, 78, 79,
165 80, 81, 82, 83, 84, 85, 86, 87,
166 88, 89, 90, 91, 92, 93, 94, 95,
167 96, 97, 98, 99, 100, 101, 102, 103,
168 104, 105, 106, 107, 108, 109, 110, 111,
169 112, 113, 114, 115, 116, 117, 118, 119,
170 120, 121, 122, 123, 124, 125, 126, 127,
171 128, 129, 130, 131, 132, 133, 134, 135,
172 136, 137, 138, 139, 140, 141, 142, 143,
173 144, 145, 146, 147, 148, 149, 150, 151,
174 152, 153, 154, 155, 156, 157, 158, 159,
175 160, 161, 162, 163, 164, 165, 166, 167,
176 168, 169, 170, 171, 172, 173, 174, 175,
177 176, 177, 178, 179, 180, 181, 182, 183,
178 184, 185, 186, 187, 188, 189, 190, 191,
179 192, 193, 194, 195, 196, 197, 198, 199,
180 200, 201, 202, 203, 204, 205, 206, 207,
181 208, 209, 210, 211, 212, 213, 214, 215,
182 216, 217, 218, 219, 220, 221, 222, 223,
183 224, 225, 226, 227, 228, 229, 230, 231,
184 232, 233, 234, 235, 236, 237, 238, 239,
185 240, 241, 242, 243, 244, 245, 246, 247,
186 248, 249, 250, 251, 252, 253, 254, 255,
187 256, 257, 258, 259, 260, 261, 262, 263,
188 },
189 .oobfree = { {2, 6}, {264, 80} },
190};
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530191
192/*
193 * Generic flash bbt descriptors
194 */
195static u8 bbt_pattern[] = {'B', 'b', 't', '0' };
196static u8 mirror_pattern[] = {'1', 't', 'b', 'B' };
197
198static struct nand_bbt_descr bbt_main_descr = {
199 .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE |
200 NAND_BBT_2BIT | NAND_BBT_VERSION,
201 .offs = 2, /* 0 on 8-bit small page */
202 .len = 4,
203 .veroffs = 6,
204 .maxblocks = 4,
205 .pattern = bbt_pattern,
206};
207
208static struct nand_bbt_descr bbt_mirror_descr = {
209 .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE |
210 NAND_BBT_2BIT | NAND_BBT_VERSION,
211 .offs = 2, /* 0 on 8-bit small page */
212 .len = 4,
213 .veroffs = 6,
214 .maxblocks = 4,
215 .pattern = mirror_pattern,
216};
217
218/*
219 * Set up the IFC hardware block and page address fields, and the ifc nand
220 * structure addr field to point to the correct IFC buffer in memory
221 */
222static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob)
223{
Scott Wood17fed142016-05-30 13:57:56 -0500224 struct nand_chip *chip = mtd_to_nand(mtd);
225 struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530226 struct fsl_ifc_ctrl *ctrl = priv->ctrl;
Jaiprakash Singhdd888062015-03-20 19:28:27 -0700227 struct fsl_ifc_runtime *ifc = ctrl->regs.rregs;
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530228 int buf_num;
229
230 ctrl->page = page_addr;
231
232 /* Program ROW0/COL0 */
Prabhakar Kushwaha62908c22014-01-18 12:28:30 +0530233 ifc_out32(&ifc->ifc_nand.row0, page_addr);
234 ifc_out32(&ifc->ifc_nand.col0, (oob ? IFC_NAND_COL_MS : 0) | column);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530235
236 buf_num = page_addr & priv->bufnum_mask;
237
238 ctrl->addr = priv->vbase + buf_num * (mtd->writesize * 2);
239 ctrl->index = column;
240
241 /* for OOB data point to the second half of the buffer */
242 if (oob)
243 ctrl->index += mtd->writesize;
244}
245
246static int is_blank(struct mtd_info *mtd, struct fsl_ifc_ctrl *ctrl,
247 unsigned int bufnum)
248{
Scott Wood17fed142016-05-30 13:57:56 -0500249 struct nand_chip *chip = mtd_to_nand(mtd);
250 struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530251 u8 __iomem *addr = priv->vbase + bufnum * (mtd->writesize * 2);
252 u32 __iomem *main = (u32 *)addr;
253 u8 __iomem *oob = addr + mtd->writesize;
254 int i;
255
256 for (i = 0; i < mtd->writesize / 4; i++) {
257 if (__raw_readl(&main[i]) != 0xffffffff)
258 return 0;
259 }
260
261 for (i = 0; i < chip->ecc.layout->eccbytes; i++) {
262 int pos = chip->ecc.layout->eccpos[i];
263
264 if (__raw_readb(&oob[pos]) != 0xff)
265 return 0;
266 }
267
268 return 1;
269}
270
271/* returns nonzero if entire page is blank */
272static int check_read_ecc(struct mtd_info *mtd, struct fsl_ifc_ctrl *ctrl,
273 u32 *eccstat, unsigned int bufnum)
274{
275 u32 reg = eccstat[bufnum / 4];
Prabhakar Kushwahacdd045d2012-01-20 18:38:14 +0530276 int errors;
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530277
Prabhakar Kushwahacdd045d2012-01-20 18:38:14 +0530278 errors = (reg >> ((3 - bufnum % 4) * 8)) & 15;
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530279
Prabhakar Kushwahacdd045d2012-01-20 18:38:14 +0530280 return errors;
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530281}
282
283/*
284 * execute IFC NAND command and wait for it to complete
285 */
286static int fsl_ifc_run_command(struct mtd_info *mtd)
287{
Scott Wood17fed142016-05-30 13:57:56 -0500288 struct nand_chip *chip = mtd_to_nand(mtd);
289 struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530290 struct fsl_ifc_ctrl *ctrl = priv->ctrl;
Jaiprakash Singhdd888062015-03-20 19:28:27 -0700291 struct fsl_ifc_runtime *ifc = ctrl->regs.rregs;
Prabhakar Kushwahad7550e12014-09-23 09:57:47 +0530292 u32 timeo = (CONFIG_SYS_HZ * 10) / 1000;
293 u32 time_start;
Scott Wood70365492015-03-19 09:20:49 -0700294 u32 eccstat[8] = {0};
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530295 int i;
296
297 /* set the chip select for NAND Transaction */
Kurt Kanzenbach1f161f82017-10-20 11:44:25 +0200298 ifc_out32(&ifc->ifc_nand.nand_csel, priv->bank << IFC_NAND_CSEL_SHIFT);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530299
300 /* start read/write seq */
Prabhakar Kushwaha62908c22014-01-18 12:28:30 +0530301 ifc_out32(&ifc->ifc_nand.nandseq_strt,
302 IFC_NAND_SEQ_STRT_FIR_STRT);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530303
304 /* wait for NAND Machine complete flag or timeout */
Prabhakar Kushwahad7550e12014-09-23 09:57:47 +0530305 time_start = get_timer(0);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530306
Prabhakar Kushwahad7550e12014-09-23 09:57:47 +0530307 while (get_timer(time_start) < timeo) {
Prabhakar Kushwaha62908c22014-01-18 12:28:30 +0530308 ctrl->status = ifc_in32(&ifc->ifc_nand.nand_evter_stat);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530309
310 if (ctrl->status & IFC_NAND_EVTER_STAT_OPC)
311 break;
312 }
313
Prabhakar Kushwaha62908c22014-01-18 12:28:30 +0530314 ifc_out32(&ifc->ifc_nand.nand_evter_stat, ctrl->status);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530315
316 if (ctrl->status & IFC_NAND_EVTER_STAT_FTOER)
317 printf("%s: Flash Time Out Error\n", __func__);
318 if (ctrl->status & IFC_NAND_EVTER_STAT_WPER)
319 printf("%s: Write Protect Error\n", __func__);
320
321 if (ctrl->eccread) {
Prabhakar Kushwahacdd045d2012-01-20 18:38:14 +0530322 int errors;
323 int bufnum = ctrl->page & priv->bufnum_mask;
324 int sector = bufnum * chip->ecc.steps;
325 int sector_end = sector + chip->ecc.steps - 1;
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530326
Scott Wood70365492015-03-19 09:20:49 -0700327 for (i = sector / 4; i <= sector_end / 4; i++) {
328 if (i >= ARRAY_SIZE(eccstat)) {
329 printf("%s: eccstat too small for %d\n",
330 __func__, i);
331 return -EIO;
332 }
333
Prabhakar Kushwaha62908c22014-01-18 12:28:30 +0530334 eccstat[i] = ifc_in32(&ifc->ifc_nand.nand_eccstat[i]);
Scott Wood70365492015-03-19 09:20:49 -0700335 }
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530336
Prabhakar Kushwahacdd045d2012-01-20 18:38:14 +0530337 for (i = sector; i <= sector_end; i++) {
338 errors = check_read_ecc(mtd, ctrl, eccstat, i);
339
340 if (errors == 15) {
341 /*
342 * Uncorrectable error.
343 * OK only if the whole page is blank.
344 *
345 * We disable ECCER reporting due to erratum
346 * IFC-A002770 -- so report it now if we
347 * see an uncorrectable error in ECCSTAT.
348 */
349 if (!is_blank(mtd, ctrl, bufnum))
350 ctrl->status |=
351 IFC_NAND_EVTER_STAT_ECCER;
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530352 break;
Prabhakar Kushwahacdd045d2012-01-20 18:38:14 +0530353 }
354
355 mtd->ecc_stats.corrected += errors;
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530356 }
357
358 ctrl->eccread = 0;
359 }
360
361 /* returns 0 on success otherwise non-zero) */
362 return ctrl->status == IFC_NAND_EVTER_STAT_OPC ? 0 : -EIO;
363}
364
365static void fsl_ifc_do_read(struct nand_chip *chip,
366 int oob,
367 struct mtd_info *mtd)
368{
Scott Wood17fed142016-05-30 13:57:56 -0500369 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 /* Program FIR/IFC_NAND_FCR0 for Small/Large page */
374 if (mtd->writesize > 512) {
Prabhakar Kushwaha62908c22014-01-18 12:28:30 +0530375 ifc_out32(&ifc->ifc_nand.nand_fir0,
376 (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
377 (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) |
378 (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP2_SHIFT) |
379 (IFC_FIR_OP_CMD1 << IFC_NAND_FIR0_OP3_SHIFT) |
380 (IFC_FIR_OP_RBCD << IFC_NAND_FIR0_OP4_SHIFT));
381 ifc_out32(&ifc->ifc_nand.nand_fir1, 0x0);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530382
Prabhakar Kushwaha62908c22014-01-18 12:28:30 +0530383 ifc_out32(&ifc->ifc_nand.nand_fcr0,
384 (NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT) |
385 (NAND_CMD_READSTART << IFC_NAND_FCR0_CMD1_SHIFT));
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530386 } else {
Prabhakar Kushwaha62908c22014-01-18 12:28:30 +0530387 ifc_out32(&ifc->ifc_nand.nand_fir0,
388 (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
389 (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) |
390 (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP2_SHIFT) |
391 (IFC_FIR_OP_RBCD << IFC_NAND_FIR0_OP3_SHIFT));
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530392
393 if (oob)
Prabhakar Kushwaha62908c22014-01-18 12:28:30 +0530394 ifc_out32(&ifc->ifc_nand.nand_fcr0,
395 NAND_CMD_READOOB << IFC_NAND_FCR0_CMD0_SHIFT);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530396 else
Prabhakar Kushwaha62908c22014-01-18 12:28:30 +0530397 ifc_out32(&ifc->ifc_nand.nand_fcr0,
398 NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530399 }
400}
401
402/* cmdfunc send commands to the IFC NAND Machine */
403static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command,
404 int column, int page_addr)
405{
Scott Wood17fed142016-05-30 13:57:56 -0500406 struct nand_chip *chip = mtd_to_nand(mtd);
407 struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530408 struct fsl_ifc_ctrl *ctrl = priv->ctrl;
Jaiprakash Singhdd888062015-03-20 19:28:27 -0700409 struct fsl_ifc_runtime *ifc = ctrl->regs.rregs;
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530410
411 /* clear the read buffer */
412 ctrl->read_bytes = 0;
413 if (command != NAND_CMD_PAGEPROG)
414 ctrl->index = 0;
415
416 switch (command) {
417 /* READ0 read the entire buffer to use hardware ECC. */
418 case NAND_CMD_READ0: {
Prabhakar Kushwaha62908c22014-01-18 12:28:30 +0530419 ifc_out32(&ifc->ifc_nand.nand_fbcr, 0);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530420 set_addr(mtd, 0, page_addr, 0);
421
422 ctrl->read_bytes = mtd->writesize + mtd->oobsize;
423 ctrl->index += column;
424
425 if (chip->ecc.mode == NAND_ECC_HW)
426 ctrl->eccread = 1;
427
428 fsl_ifc_do_read(chip, 0, mtd);
429 fsl_ifc_run_command(mtd);
430 return;
431 }
432
433 /* READOOB reads only the OOB because no ECC is performed. */
434 case NAND_CMD_READOOB:
Prabhakar Kushwaha62908c22014-01-18 12:28:30 +0530435 ifc_out32(&ifc->ifc_nand.nand_fbcr, mtd->oobsize - column);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530436 set_addr(mtd, column, page_addr, 1);
437
438 ctrl->read_bytes = mtd->writesize + mtd->oobsize;
439
440 fsl_ifc_do_read(chip, 1, mtd);
441 fsl_ifc_run_command(mtd);
442
443 return;
444
445 /* READID must read all possible bytes while CEB is active */
446 case NAND_CMD_READID:
Prabhakar Kushwahaf31cf532012-04-08 18:57:18 +0000447 case NAND_CMD_PARAM: {
448 int timing = IFC_FIR_OP_RB;
449 if (command == NAND_CMD_PARAM)
450 timing = IFC_FIR_OP_RBCD;
451
Prabhakar Kushwaha62908c22014-01-18 12:28:30 +0530452 ifc_out32(&ifc->ifc_nand.nand_fir0,
453 (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
454 (IFC_FIR_OP_UA << IFC_NAND_FIR0_OP1_SHIFT) |
455 (timing << IFC_NAND_FIR0_OP2_SHIFT));
456 ifc_out32(&ifc->ifc_nand.nand_fcr0,
457 command << IFC_NAND_FCR0_CMD0_SHIFT);
458 ifc_out32(&ifc->ifc_nand.row3, column);
Prabhakar Kushwahaf31cf532012-04-08 18:57:18 +0000459
460 /*
461 * although currently it's 8 bytes for READID, we always read
462 * the maximum 256 bytes(for PARAM)
463 */
Prabhakar Kushwaha62908c22014-01-18 12:28:30 +0530464 ifc_out32(&ifc->ifc_nand.nand_fbcr, 256);
Prabhakar Kushwahaf31cf532012-04-08 18:57:18 +0000465 ctrl->read_bytes = 256;
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530466
467 set_addr(mtd, 0, 0, 0);
468 fsl_ifc_run_command(mtd);
469 return;
Prabhakar Kushwahaf31cf532012-04-08 18:57:18 +0000470 }
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530471
472 /* ERASE1 stores the block and page address */
473 case NAND_CMD_ERASE1:
474 set_addr(mtd, 0, page_addr, 0);
475 return;
476
477 /* ERASE2 uses the block and page address from ERASE1 */
478 case NAND_CMD_ERASE2:
Prabhakar Kushwaha62908c22014-01-18 12:28:30 +0530479 ifc_out32(&ifc->ifc_nand.nand_fir0,
480 (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
481 (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP1_SHIFT) |
482 (IFC_FIR_OP_CMD1 << IFC_NAND_FIR0_OP2_SHIFT));
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530483
Prabhakar Kushwaha62908c22014-01-18 12:28:30 +0530484 ifc_out32(&ifc->ifc_nand.nand_fcr0,
485 (NAND_CMD_ERASE1 << IFC_NAND_FCR0_CMD0_SHIFT) |
486 (NAND_CMD_ERASE2 << IFC_NAND_FCR0_CMD1_SHIFT));
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530487
Prabhakar Kushwaha62908c22014-01-18 12:28:30 +0530488 ifc_out32(&ifc->ifc_nand.nand_fbcr, 0);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530489 ctrl->read_bytes = 0;
490 fsl_ifc_run_command(mtd);
491 return;
492
493 /* SEQIN sets up the addr buffer and all registers except the length */
494 case NAND_CMD_SEQIN: {
495 u32 nand_fcr0;
496 ctrl->column = column;
497 ctrl->oob = 0;
498
499 if (mtd->writesize > 512) {
500 nand_fcr0 =
501 (NAND_CMD_SEQIN << IFC_NAND_FCR0_CMD0_SHIFT) |
Prabhakar Kushwaha18e6bde2013-10-03 11:35:35 +0530502 (NAND_CMD_STATUS << IFC_NAND_FCR0_CMD1_SHIFT) |
503 (NAND_CMD_PAGEPROG << IFC_NAND_FCR0_CMD2_SHIFT);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530504
Prabhakar Kushwaha62908c22014-01-18 12:28:30 +0530505 ifc_out32(&ifc->ifc_nand.nand_fir0,
506 (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
507 (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) |
508 (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP2_SHIFT) |
509 (IFC_FIR_OP_WBCD <<
510 IFC_NAND_FIR0_OP3_SHIFT) |
511 (IFC_FIR_OP_CMD2 << IFC_NAND_FIR0_OP4_SHIFT));
512 ifc_out32(&ifc->ifc_nand.nand_fir1,
513 (IFC_FIR_OP_CW1 << IFC_NAND_FIR1_OP5_SHIFT) |
514 (IFC_FIR_OP_RDSTAT <<
Prabhakar Kushwaha18e6bde2013-10-03 11:35:35 +0530515 IFC_NAND_FIR1_OP6_SHIFT) |
Prabhakar Kushwaha62908c22014-01-18 12:28:30 +0530516 (IFC_FIR_OP_NOP << IFC_NAND_FIR1_OP7_SHIFT));
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530517 } else {
518 nand_fcr0 = ((NAND_CMD_PAGEPROG <<
519 IFC_NAND_FCR0_CMD1_SHIFT) |
520 (NAND_CMD_SEQIN <<
Prabhakar Kushwaha18e6bde2013-10-03 11:35:35 +0530521 IFC_NAND_FCR0_CMD2_SHIFT) |
522 (NAND_CMD_STATUS <<
523 IFC_NAND_FCR0_CMD3_SHIFT));
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530524
Prabhakar Kushwaha62908c22014-01-18 12:28:30 +0530525 ifc_out32(&ifc->ifc_nand.nand_fir0,
526 (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
527 (IFC_FIR_OP_CMD2 << IFC_NAND_FIR0_OP1_SHIFT) |
528 (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP2_SHIFT) |
529 (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP3_SHIFT) |
530 (IFC_FIR_OP_WBCD << IFC_NAND_FIR0_OP4_SHIFT));
531 ifc_out32(&ifc->ifc_nand.nand_fir1,
532 (IFC_FIR_OP_CMD1 << IFC_NAND_FIR1_OP5_SHIFT) |
533 (IFC_FIR_OP_CW3 << IFC_NAND_FIR1_OP6_SHIFT) |
534 (IFC_FIR_OP_RDSTAT <<
Prabhakar Kushwaha18e6bde2013-10-03 11:35:35 +0530535 IFC_NAND_FIR1_OP7_SHIFT) |
Prabhakar Kushwaha62908c22014-01-18 12:28:30 +0530536 (IFC_FIR_OP_NOP << IFC_NAND_FIR1_OP8_SHIFT));
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530537
Prabhakar Kushwaha0ed5e772012-01-20 18:39:05 +0530538 if (column >= mtd->writesize)
539 nand_fcr0 |=
540 NAND_CMD_READOOB << IFC_NAND_FCR0_CMD0_SHIFT;
541 else
542 nand_fcr0 |=
543 NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT;
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530544 }
545
Prabhakar Kushwaha0ed5e772012-01-20 18:39:05 +0530546 if (column >= mtd->writesize) {
547 /* OOB area --> READOOB */
548 column -= mtd->writesize;
549 ctrl->oob = 1;
550 }
Prabhakar Kushwaha62908c22014-01-18 12:28:30 +0530551 ifc_out32(&ifc->ifc_nand.nand_fcr0, nand_fcr0);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530552 set_addr(mtd, column, page_addr, ctrl->oob);
553 return;
554 }
555
556 /* PAGEPROG reuses all of the setup from SEQIN and adds the length */
557 case NAND_CMD_PAGEPROG:
558 if (ctrl->oob)
Prabhakar Kushwaha62908c22014-01-18 12:28:30 +0530559 ifc_out32(&ifc->ifc_nand.nand_fbcr,
560 ctrl->index - ctrl->column);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530561 else
Prabhakar Kushwaha62908c22014-01-18 12:28:30 +0530562 ifc_out32(&ifc->ifc_nand.nand_fbcr, 0);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530563
564 fsl_ifc_run_command(mtd);
565 return;
566
567 case NAND_CMD_STATUS:
Prabhakar Kushwaha62908c22014-01-18 12:28:30 +0530568 ifc_out32(&ifc->ifc_nand.nand_fir0,
569 (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
570 (IFC_FIR_OP_RB << IFC_NAND_FIR0_OP1_SHIFT));
571 ifc_out32(&ifc->ifc_nand.nand_fcr0,
572 NAND_CMD_STATUS << IFC_NAND_FCR0_CMD0_SHIFT);
573 ifc_out32(&ifc->ifc_nand.nand_fbcr, 1);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530574 set_addr(mtd, 0, 0, 0);
575 ctrl->read_bytes = 1;
576
577 fsl_ifc_run_command(mtd);
578
Scott Wood3ea94ed2015-06-26 19:03:26 -0500579 /*
580 * The chip always seems to report that it is
581 * write-protected, even when it is not.
582 */
583 if (chip->options & NAND_BUSWIDTH_16)
584 ifc_out16(ctrl->addr,
585 ifc_in16(ctrl->addr) | NAND_STATUS_WP);
586 else
587 out_8(ctrl->addr, in_8(ctrl->addr) | NAND_STATUS_WP);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530588 return;
589
590 case NAND_CMD_RESET:
Prabhakar Kushwaha62908c22014-01-18 12:28:30 +0530591 ifc_out32(&ifc->ifc_nand.nand_fir0,
592 IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT);
593 ifc_out32(&ifc->ifc_nand.nand_fcr0,
594 NAND_CMD_RESET << IFC_NAND_FCR0_CMD0_SHIFT);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530595 fsl_ifc_run_command(mtd);
596 return;
597
598 default:
599 printf("%s: error, unsupported command 0x%x.\n",
600 __func__, command);
601 }
602}
603
604/*
605 * Write buf to the IFC NAND Controller Data Buffer
606 */
607static void fsl_ifc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
608{
Scott Wood17fed142016-05-30 13:57:56 -0500609 struct nand_chip *chip = mtd_to_nand(mtd);
610 struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530611 struct fsl_ifc_ctrl *ctrl = priv->ctrl;
612 unsigned int bufsize = mtd->writesize + mtd->oobsize;
613
614 if (len <= 0) {
615 printf("%s of %d bytes", __func__, len);
616 ctrl->status = 0;
617 return;
618 }
619
620 if ((unsigned int)len > bufsize - ctrl->index) {
621 printf("%s beyond end of buffer "
622 "(%d requested, %u available)\n",
623 __func__, len, bufsize - ctrl->index);
624 len = bufsize - ctrl->index;
625 }
626
Scott Wood3ea94ed2015-06-26 19:03:26 -0500627 memcpy_toio(ctrl->addr + ctrl->index, buf, len);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530628 ctrl->index += len;
629}
630
631/*
632 * read a byte from either the IFC hardware buffer if it has any data left
633 * otherwise issue a command to read a single byte.
634 */
635static u8 fsl_ifc_read_byte(struct mtd_info *mtd)
636{
Scott Wood17fed142016-05-30 13:57:56 -0500637 struct nand_chip *chip = mtd_to_nand(mtd);
638 struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530639 struct fsl_ifc_ctrl *ctrl = priv->ctrl;
Scott Wood3ea94ed2015-06-26 19:03:26 -0500640 unsigned int offset;
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530641
Scott Wood3ea94ed2015-06-26 19:03:26 -0500642 /*
643 * If there are still bytes in the IFC buffer, then use the
644 * next byte.
645 */
646 if (ctrl->index < ctrl->read_bytes) {
647 offset = ctrl->index++;
648 return in_8(ctrl->addr + offset);
649 }
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530650
651 printf("%s beyond end of buffer\n", __func__);
652 return ERR_BYTE;
653}
654
655/*
656 * Read two bytes from the IFC hardware buffer
657 * read function for 16-bit buswith
658 */
659static uint8_t fsl_ifc_read_byte16(struct mtd_info *mtd)
660{
Scott Wood17fed142016-05-30 13:57:56 -0500661 struct nand_chip *chip = mtd_to_nand(mtd);
662 struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530663 struct fsl_ifc_ctrl *ctrl = priv->ctrl;
664 uint16_t data;
665
666 /*
667 * If there are still bytes in the IFC buffer, then use the
668 * next byte.
669 */
670 if (ctrl->index < ctrl->read_bytes) {
Scott Wood3ea94ed2015-06-26 19:03:26 -0500671 data = ifc_in16(ctrl->addr + ctrl->index);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530672 ctrl->index += 2;
673 return (uint8_t)data;
674 }
675
676 printf("%s beyond end of buffer\n", __func__);
677 return ERR_BYTE;
678}
679
680/*
681 * Read from the IFC Controller Data Buffer
682 */
683static void fsl_ifc_read_buf(struct mtd_info *mtd, u8 *buf, int len)
684{
Scott Wood17fed142016-05-30 13:57:56 -0500685 struct nand_chip *chip = mtd_to_nand(mtd);
686 struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530687 struct fsl_ifc_ctrl *ctrl = priv->ctrl;
688 int avail;
689
690 if (len < 0)
691 return;
692
693 avail = min((unsigned int)len, ctrl->read_bytes - ctrl->index);
Scott Wood3ea94ed2015-06-26 19:03:26 -0500694 memcpy_fromio(buf, ctrl->addr + ctrl->index, avail);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530695 ctrl->index += avail;
696
697 if (len > avail)
698 printf("%s beyond end of buffer "
699 "(%d requested, %d available)\n",
700 __func__, len, avail);
701}
702
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530703/* This function is called after Program and Erase Operations to
704 * check for success or failure.
705 */
706static int fsl_ifc_wait(struct mtd_info *mtd, struct nand_chip *chip)
707{
Scott Wood17fed142016-05-30 13:57:56 -0500708 struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530709 struct fsl_ifc_ctrl *ctrl = priv->ctrl;
Jaiprakash Singhdd888062015-03-20 19:28:27 -0700710 struct fsl_ifc_runtime *ifc = ctrl->regs.rregs;
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530711 u32 nand_fsr;
712
713 if (ctrl->status != IFC_NAND_EVTER_STAT_OPC)
714 return NAND_STATUS_FAIL;
715
716 /* Use READ_STATUS command, but wait for the device to be ready */
Prabhakar Kushwaha62908c22014-01-18 12:28:30 +0530717 ifc_out32(&ifc->ifc_nand.nand_fir0,
718 (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
719 (IFC_FIR_OP_RDSTAT << IFC_NAND_FIR0_OP1_SHIFT));
720 ifc_out32(&ifc->ifc_nand.nand_fcr0, NAND_CMD_STATUS <<
721 IFC_NAND_FCR0_CMD0_SHIFT);
722 ifc_out32(&ifc->ifc_nand.nand_fbcr, 1);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530723 set_addr(mtd, 0, 0, 0);
724 ctrl->read_bytes = 1;
725
726 fsl_ifc_run_command(mtd);
727
728 if (ctrl->status != IFC_NAND_EVTER_STAT_OPC)
729 return NAND_STATUS_FAIL;
730
Prabhakar Kushwaha62908c22014-01-18 12:28:30 +0530731 nand_fsr = ifc_in32(&ifc->ifc_nand.nand_fsr);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530732
733 /* Chip sometimes reporting write protect even when it's not */
734 nand_fsr = nand_fsr | NAND_STATUS_WP;
735 return nand_fsr;
736}
737
Sergey Lapin3a38a552013-01-14 03:46:50 +0000738static int fsl_ifc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
739 uint8_t *buf, int oob_required, int page)
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530740{
Scott Wood17fed142016-05-30 13:57:56 -0500741 struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530742 struct fsl_ifc_ctrl *ctrl = priv->ctrl;
743
744 fsl_ifc_read_buf(mtd, buf, mtd->writesize);
745 fsl_ifc_read_buf(mtd, chip->oob_poi, mtd->oobsize);
746
747 if (ctrl->status != IFC_NAND_EVTER_STAT_OPC)
748 mtd->ecc_stats.failed++;
749
750 return 0;
751}
752
753/* ECC will be calculated automatically, and errors will be detected in
754 * waitfunc.
755 */
Sergey Lapin3a38a552013-01-14 03:46:50 +0000756static int fsl_ifc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
Scott Wood46e13102016-05-30 13:57:57 -0500757 const uint8_t *buf, int oob_required, int page)
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530758{
759 fsl_ifc_write_buf(mtd, buf, mtd->writesize);
760 fsl_ifc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
Sergey Lapin3a38a552013-01-14 03:46:50 +0000761
762 return 0;
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530763}
764
765static void fsl_ifc_ctrl_init(void)
766{
Jaiprakash Singhdd888062015-03-20 19:28:27 -0700767 uint32_t ver = 0;
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530768 ifc_ctrl = kzalloc(sizeof(*ifc_ctrl), GFP_KERNEL);
769 if (!ifc_ctrl)
770 return;
771
Jaiprakash Singhdd888062015-03-20 19:28:27 -0700772 ifc_ctrl->regs.gregs = IFC_FCM_BASE_ADDR;
773
774 ver = ifc_in32(&ifc_ctrl->regs.gregs->ifc_rev);
775 if (ver >= FSL_IFC_V2_0_0)
776 ifc_ctrl->regs.rregs =
777 (void *)CONFIG_SYS_IFC_ADDR + IFC_RREGS_64KOFFSET;
778 else
779 ifc_ctrl->regs.rregs =
780 (void *)CONFIG_SYS_IFC_ADDR + IFC_RREGS_4KOFFSET;
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530781
782 /* clear event registers */
Jaiprakash Singhdd888062015-03-20 19:28:27 -0700783 ifc_out32(&ifc_ctrl->regs.rregs->ifc_nand.nand_evter_stat, ~0U);
784 ifc_out32(&ifc_ctrl->regs.rregs->ifc_nand.pgrdcmpl_evt_stat, ~0U);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530785
786 /* Enable error and event for any detected errors */
Jaiprakash Singhdd888062015-03-20 19:28:27 -0700787 ifc_out32(&ifc_ctrl->regs.rregs->ifc_nand.nand_evter_en,
Prabhakar Kushwaha62908c22014-01-18 12:28:30 +0530788 IFC_NAND_EVTER_EN_OPC_EN |
789 IFC_NAND_EVTER_EN_PGRDCMPL_EN |
790 IFC_NAND_EVTER_EN_FTOER_EN |
791 IFC_NAND_EVTER_EN_WPER_EN);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530792
Jaiprakash Singhdd888062015-03-20 19:28:27 -0700793 ifc_out32(&ifc_ctrl->regs.rregs->ifc_nand.ncfgr, 0x0);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530794}
795
796static void fsl_ifc_select_chip(struct mtd_info *mtd, int chip)
797{
798}
799
Kurt Kanzenbach1f161f82017-10-20 11:44:25 +0200800static int fsl_ifc_sram_init(struct fsl_ifc_mtd *priv, uint32_t ver)
Prabhakar Kushwahadccbf352012-09-12 22:26:05 +0000801{
Jaiprakash Singhdd888062015-03-20 19:28:27 -0700802 struct fsl_ifc_runtime *ifc = ifc_ctrl->regs.rregs;
Prabhakar Kushwahadccbf352012-09-12 22:26:05 +0000803 uint32_t cs = 0, csor = 0, csor_8k = 0, csor_ext = 0;
Prabhakar Kushwaha82efc812014-06-12 12:14:00 +0530804 uint32_t ncfgr = 0;
Prabhakar Kushwahad7550e12014-09-23 09:57:47 +0530805 u32 timeo = (CONFIG_SYS_HZ * 10) / 1000;
806 u32 time_start;
Prabhakar Kushwahadccbf352012-09-12 22:26:05 +0000807
Prabhakar Kushwaha82efc812014-06-12 12:14:00 +0530808 if (ver > FSL_IFC_V1_1_0) {
809 ncfgr = ifc_in32(&ifc->ifc_nand.ncfgr);
810 ifc_out32(&ifc->ifc_nand.ncfgr, ncfgr | IFC_NAND_SRAM_INIT_EN);
811
812 /* wait for SRAM_INIT bit to be clear or timeout */
Prabhakar Kushwahad7550e12014-09-23 09:57:47 +0530813 time_start = get_timer(0);
814 while (get_timer(time_start) < timeo) {
Prabhakar Kushwaha82efc812014-06-12 12:14:00 +0530815 ifc_ctrl->status =
816 ifc_in32(&ifc->ifc_nand.nand_evter_stat);
817
818 if (!(ifc_ctrl->status & IFC_NAND_SRAM_INIT_EN))
819 return 0;
820 }
821 printf("fsl-ifc: Failed to Initialise SRAM\n");
822 return 1;
823 }
824
Kurt Kanzenbach1f161f82017-10-20 11:44:25 +0200825 cs = priv->bank;
Prabhakar Kushwahadccbf352012-09-12 22:26:05 +0000826
827 /* Save CSOR and CSOR_ext */
Jaiprakash Singhdd888062015-03-20 19:28:27 -0700828 csor = ifc_in32(&ifc_ctrl->regs.gregs->csor_cs[cs].csor);
829 csor_ext = ifc_in32(&ifc_ctrl->regs.gregs->csor_cs[cs].csor_ext);
Prabhakar Kushwahadccbf352012-09-12 22:26:05 +0000830
831 /* chage PageSize 8K and SpareSize 1K*/
832 csor_8k = (csor & ~(CSOR_NAND_PGS_MASK)) | 0x0018C000;
Jaiprakash Singhdd888062015-03-20 19:28:27 -0700833 ifc_out32(&ifc_ctrl->regs.gregs->csor_cs[cs].csor, csor_8k);
834 ifc_out32(&ifc_ctrl->regs.gregs->csor_cs[cs].csor_ext, 0x0000400);
Prabhakar Kushwahadccbf352012-09-12 22:26:05 +0000835
836 /* READID */
Prabhakar Kushwaha62908c22014-01-18 12:28:30 +0530837 ifc_out32(&ifc->ifc_nand.nand_fir0,
838 (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
839 (IFC_FIR_OP_UA << IFC_NAND_FIR0_OP1_SHIFT) |
840 (IFC_FIR_OP_RB << IFC_NAND_FIR0_OP2_SHIFT));
841 ifc_out32(&ifc->ifc_nand.nand_fcr0,
842 NAND_CMD_READID << IFC_NAND_FCR0_CMD0_SHIFT);
843 ifc_out32(&ifc->ifc_nand.row3, 0x0);
Prabhakar Kushwahadccbf352012-09-12 22:26:05 +0000844
Prabhakar Kushwaha62908c22014-01-18 12:28:30 +0530845 ifc_out32(&ifc->ifc_nand.nand_fbcr, 0x0);
Prabhakar Kushwahadccbf352012-09-12 22:26:05 +0000846
847 /* Program ROW0/COL0 */
Prabhakar Kushwaha62908c22014-01-18 12:28:30 +0530848 ifc_out32(&ifc->ifc_nand.row0, 0x0);
849 ifc_out32(&ifc->ifc_nand.col0, 0x0);
Prabhakar Kushwahadccbf352012-09-12 22:26:05 +0000850
851 /* set the chip select for NAND Transaction */
Kurt Kanzenbach1f161f82017-10-20 11:44:25 +0200852 ifc_out32(&ifc->ifc_nand.nand_csel, priv->bank << IFC_NAND_CSEL_SHIFT);
Prabhakar Kushwahadccbf352012-09-12 22:26:05 +0000853
854 /* start read seq */
Prabhakar Kushwaha62908c22014-01-18 12:28:30 +0530855 ifc_out32(&ifc->ifc_nand.nandseq_strt, IFC_NAND_SEQ_STRT_FIR_STRT);
Prabhakar Kushwahadccbf352012-09-12 22:26:05 +0000856
Prabhakar Kushwahad7550e12014-09-23 09:57:47 +0530857 time_start = get_timer(0);
Prabhakar Kushwahadccbf352012-09-12 22:26:05 +0000858
Prabhakar Kushwahad7550e12014-09-23 09:57:47 +0530859 while (get_timer(time_start) < timeo) {
Prabhakar Kushwaha62908c22014-01-18 12:28:30 +0530860 ifc_ctrl->status = ifc_in32(&ifc->ifc_nand.nand_evter_stat);
Prabhakar Kushwahadccbf352012-09-12 22:26:05 +0000861
862 if (ifc_ctrl->status & IFC_NAND_EVTER_STAT_OPC)
863 break;
864 }
865
Prabhakar Kushwaha82efc812014-06-12 12:14:00 +0530866 if (ifc_ctrl->status != IFC_NAND_EVTER_STAT_OPC) {
867 printf("fsl-ifc: Failed to Initialise SRAM\n");
868 return 1;
869 }
870
Prabhakar Kushwaha62908c22014-01-18 12:28:30 +0530871 ifc_out32(&ifc->ifc_nand.nand_evter_stat, ifc_ctrl->status);
Prabhakar Kushwahadccbf352012-09-12 22:26:05 +0000872
873 /* Restore CSOR and CSOR_ext */
Jaiprakash Singhdd888062015-03-20 19:28:27 -0700874 ifc_out32(&ifc_ctrl->regs.gregs->csor_cs[cs].csor, csor);
875 ifc_out32(&ifc_ctrl->regs.gregs->csor_cs[cs].csor_ext, csor_ext);
Prabhakar Kushwaha82efc812014-06-12 12:14:00 +0530876
877 return 0;
Prabhakar Kushwahadccbf352012-09-12 22:26:05 +0000878}
879
Prabhakar Kushwaha895d0392013-04-04 18:44:06 +0000880static int fsl_ifc_chip_init(int devnum, u8 *addr)
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530881{
Scott Wood2c1b7e12016-05-30 13:57:55 -0500882 struct mtd_info *mtd;
Prabhakar Kushwaha895d0392013-04-04 18:44:06 +0000883 struct nand_chip *nand;
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530884 struct fsl_ifc_mtd *priv;
885 struct nand_ecclayout *layout;
Jaiprakash Singhdd888062015-03-20 19:28:27 -0700886 struct fsl_ifc_fcm *gregs = NULL;
Prabhakar Kushwahadccbf352012-09-12 22:26:05 +0000887 uint32_t cspr = 0, csor = 0, ver = 0;
Prabhakar Kushwaha82efc812014-06-12 12:14:00 +0530888 int ret = 0;
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530889
890 if (!ifc_ctrl) {
891 fsl_ifc_ctrl_init();
892 if (!ifc_ctrl)
893 return -1;
894 }
895
896 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
897 if (!priv)
898 return -ENOMEM;
899
900 priv->ctrl = ifc_ctrl;
Prabhakar Kushwaha895d0392013-04-04 18:44:06 +0000901 priv->vbase = addr;
Jaiprakash Singhdd888062015-03-20 19:28:27 -0700902 gregs = ifc_ctrl->regs.gregs;
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530903
904 /* Find which chip select it is connected to.
905 */
906 for (priv->bank = 0; priv->bank < MAX_BANKS; priv->bank++) {
Prabhakar Kushwaha895d0392013-04-04 18:44:06 +0000907 phys_addr_t phys_addr = virt_to_phys(addr);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530908
Jaiprakash Singhdd888062015-03-20 19:28:27 -0700909 cspr = ifc_in32(&gregs->cspr_cs[priv->bank].cspr);
910 csor = ifc_in32(&gregs->csor_cs[priv->bank].csor);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530911
912 if ((cspr & CSPR_V) && (cspr & CSPR_MSEL) == CSPR_MSEL_NAND &&
Kurt Kanzenbach1f161f82017-10-20 11:44:25 +0200913 (cspr & CSPR_BA) == CSPR_PHYS_ADDR(phys_addr))
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530914 break;
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530915 }
916
917 if (priv->bank >= MAX_BANKS) {
918 printf("%s: address did not match any "
919 "chip selects\n", __func__);
Prabhakar Kushwahaae25e882012-04-10 22:48:27 +0000920 kfree(priv);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530921 return -ENODEV;
922 }
923
Prabhakar Kushwaha895d0392013-04-04 18:44:06 +0000924 nand = &priv->chip;
Scott Wood17fed142016-05-30 13:57:56 -0500925 mtd = nand_to_mtd(nand);
Prabhakar Kushwaha895d0392013-04-04 18:44:06 +0000926
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530927 ifc_ctrl->chips[priv->bank] = priv;
928
929 /* fill in nand_chip structure */
930 /* set up function call table */
931
932 nand->write_buf = fsl_ifc_write_buf;
933 nand->read_buf = fsl_ifc_read_buf;
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530934 nand->select_chip = fsl_ifc_select_chip;
935 nand->cmdfunc = fsl_ifc_cmdfunc;
936 nand->waitfunc = fsl_ifc_wait;
937
938 /* set up nand options */
939 nand->bbt_td = &bbt_main_descr;
940 nand->bbt_md = &bbt_mirror_descr;
941
942 /* set up nand options */
Sergey Lapin3a38a552013-01-14 03:46:50 +0000943 nand->options = NAND_NO_SUBPAGE_WRITE;
944 nand->bbt_options = NAND_BBT_USE_FLASH;
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530945
946 if (cspr & CSPR_PORT_SIZE_16) {
947 nand->read_byte = fsl_ifc_read_byte16;
948 nand->options |= NAND_BUSWIDTH_16;
949 } else {
950 nand->read_byte = fsl_ifc_read_byte;
951 }
952
953 nand->controller = &ifc_ctrl->controller;
Scott Wood17fed142016-05-30 13:57:56 -0500954 nand_set_controller_data(nand, priv);
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530955
956 nand->ecc.read_page = fsl_ifc_read_page;
957 nand->ecc.write_page = fsl_ifc_write_page;
958
959 /* Hardware generates ECC per 512 Bytes */
960 nand->ecc.size = 512;
961 nand->ecc.bytes = 8;
962
963 switch (csor & CSOR_NAND_PGS_MASK) {
964 case CSOR_NAND_PGS_512:
965 if (nand->options & NAND_BUSWIDTH_16) {
966 layout = &oob_512_16bit_ecc4;
967 } else {
968 layout = &oob_512_8bit_ecc4;
969
970 /* Avoid conflict with bad block marker */
971 bbt_main_descr.offs = 0;
972 bbt_mirror_descr.offs = 0;
973 }
974
Sergey Lapin3a38a552013-01-14 03:46:50 +0000975 nand->ecc.strength = 4;
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530976 priv->bufnum_mask = 15;
977 break;
978
979 case CSOR_NAND_PGS_2K:
980 layout = &oob_2048_ecc4;
Sergey Lapin3a38a552013-01-14 03:46:50 +0000981 nand->ecc.strength = 4;
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530982 priv->bufnum_mask = 3;
983 break;
984
985 case CSOR_NAND_PGS_4K:
986 if ((csor & CSOR_NAND_ECC_MODE_MASK) ==
987 CSOR_NAND_ECC_MODE_4) {
988 layout = &oob_4096_ecc4;
Sergey Lapin3a38a552013-01-14 03:46:50 +0000989 nand->ecc.strength = 4;
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530990 } else {
991 layout = &oob_4096_ecc8;
Sergey Lapin3a38a552013-01-14 03:46:50 +0000992 nand->ecc.strength = 8;
Dipen Dudhat9eae0832011-03-22 09:27:39 +0530993 nand->ecc.bytes = 16;
994 }
995
996 priv->bufnum_mask = 1;
997 break;
998
Prabhakar Kushwahaa3aaf1d2013-10-04 10:05:36 +0530999 case CSOR_NAND_PGS_8K:
1000 if ((csor & CSOR_NAND_ECC_MODE_MASK) ==
1001 CSOR_NAND_ECC_MODE_4) {
1002 layout = &oob_8192_ecc4;
1003 nand->ecc.strength = 4;
1004 } else {
1005 layout = &oob_8192_ecc8;
1006 nand->ecc.strength = 8;
1007 nand->ecc.bytes = 16;
1008 }
1009
1010 priv->bufnum_mask = 0;
1011 break;
1012
1013
Dipen Dudhat9eae0832011-03-22 09:27:39 +05301014 default:
1015 printf("ifc nand: bad csor %#x: bad page size\n", csor);
1016 return -ENODEV;
1017 }
1018
1019 /* Must also set CSOR_NAND_ECC_ENC_EN if DEC_EN set */
1020 if (csor & CSOR_NAND_ECC_DEC_EN) {
1021 nand->ecc.mode = NAND_ECC_HW;
1022 nand->ecc.layout = layout;
1023 } else {
1024 nand->ecc.mode = NAND_ECC_SOFT;
1025 }
1026
Jaiprakash Singhdd888062015-03-20 19:28:27 -07001027 ver = ifc_in32(&gregs->ifc_rev);
Prabhakar Kushwaha82efc812014-06-12 12:14:00 +05301028 if (ver >= FSL_IFC_V1_1_0)
Kurt Kanzenbach1f161f82017-10-20 11:44:25 +02001029 ret = fsl_ifc_sram_init(priv, ver);
Prabhakar Kushwaha82efc812014-06-12 12:14:00 +05301030 if (ret)
1031 return ret;
Prabhakar Kushwahadccbf352012-09-12 22:26:05 +00001032
Prabhakar Kushwaha5c23a822014-06-14 08:48:19 +05301033 if (ver >= FSL_IFC_V2_0_0)
1034 priv->bufnum_mask = (priv->bufnum_mask * 2) + 1;
1035
Prabhakar Kushwaha895d0392013-04-04 18:44:06 +00001036 ret = nand_scan_ident(mtd, 1, NULL);
1037 if (ret)
1038 return ret;
1039
1040 ret = nand_scan_tail(mtd);
1041 if (ret)
1042 return ret;
1043
Scott Wood2c1b7e12016-05-30 13:57:55 -05001044 ret = nand_register(devnum, mtd);
Prabhakar Kushwaha895d0392013-04-04 18:44:06 +00001045 if (ret)
1046 return ret;
Dipen Dudhat9eae0832011-03-22 09:27:39 +05301047 return 0;
1048}
Prabhakar Kushwaha895d0392013-04-04 18:44:06 +00001049
1050#ifndef CONFIG_SYS_NAND_BASE_LIST
1051#define CONFIG_SYS_NAND_BASE_LIST { CONFIG_SYS_NAND_BASE }
1052#endif
1053
1054static unsigned long base_address[CONFIG_SYS_MAX_NAND_DEVICE] =
1055 CONFIG_SYS_NAND_BASE_LIST;
1056
1057void board_nand_init(void)
1058{
1059 int i;
1060
1061 for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++)
1062 fsl_ifc_chip_init(i, (u8 *)base_address[i]);
1063}