blob: 87f03410666aef3a328f00030b1d113015a7f96b [file] [log] [blame]
Guennadi Liakhovetskie0056b32008-08-31 00:39:47 +02001/*
2 * (C) Copyright 2006 DENX Software Engineering
3 *
4 * Implementation for U-Boot 1.1.6 by Samsung
5 *
6 * (C) Copyright 2008
7 * Guennadi Liakhovetki, DENX Software Engineering, <lg@denx.de>
8 *
9 * See file CREDITS for list of people who contributed to this
10 * project.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License as
14 * published by the Free Software Foundation; either version 2 of
15 * the License, or (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
25 * MA 02111-1307 USA
26 */
27
28#include <common.h>
29
30#include <nand.h>
Simon Schwarz56c91bc2011-10-31 06:34:45 +000031#include <linux/mtd/nand.h>
32
Minkyu Kang47e801b2009-11-04 16:07:59 +090033#include <asm/arch/s3c6400.h>
Guennadi Liakhovetskie0056b32008-08-31 00:39:47 +020034
35#include <asm/io.h>
36#include <asm/errno.h>
37
38#define MAX_CHIPS 2
39static int nand_cs[MAX_CHIPS] = {0, 1};
40
41#ifdef CONFIG_NAND_SPL
42#define printf(arg...) do {} while (0)
43#endif
44
45/* Nand flash definition values by jsgood */
46#ifdef S3C_NAND_DEBUG
47/*
48 * Function to print out oob buffer for debugging
49 * Written by jsgood
50 */
51static void print_oob(const char *header, struct mtd_info *mtd)
52{
53 int i;
54 struct nand_chip *chip = mtd->priv;
55
56 printf("%s:\t", header);
57
58 for (i = 0; i < 64; i++)
59 printf("%02x ", chip->oob_poi[i]);
60
61 printf("\n");
62}
63#endif /* S3C_NAND_DEBUG */
64
Guennadi Liakhovetskie0056b32008-08-31 00:39:47 +020065static void s3c_nand_select_chip(struct mtd_info *mtd, int chip)
66{
67 int ctrl = readl(NFCONT);
68
69 switch (chip) {
70 case -1:
71 ctrl |= 6;
72 break;
73 case 0:
74 ctrl &= ~2;
75 break;
76 case 1:
77 ctrl &= ~4;
78 break;
79 default:
80 return;
81 }
82
83 writel(ctrl, NFCONT);
84}
85
86/*
87 * Hardware specific access to control-lines function
88 * Written by jsgood
89 */
90static void s3c_nand_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
91{
92 struct nand_chip *this = mtd->priv;
93
94 if (ctrl & NAND_CTRL_CHANGE) {
95 if (ctrl & NAND_CLE)
96 this->IO_ADDR_W = (void __iomem *)NFCMMD;
97 else if (ctrl & NAND_ALE)
98 this->IO_ADDR_W = (void __iomem *)NFADDR;
99 else
100 this->IO_ADDR_W = (void __iomem *)NFDATA;
101 if (ctrl & NAND_NCE)
102 s3c_nand_select_chip(mtd, *(int *)this->priv);
103 else
104 s3c_nand_select_chip(mtd, -1);
105 }
106
107 if (cmd != NAND_CMD_NONE)
108 writeb(cmd, this->IO_ADDR_W);
109}
110
111/*
112 * Function for checking device ready pin
113 * Written by jsgood
114 */
115static int s3c_nand_device_ready(struct mtd_info *mtdinfo)
116{
117 return !!(readl(NFSTAT) & NFSTAT_RnB);
118}
119
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200120#ifdef CONFIG_SYS_S3C_NAND_HWECC
Guennadi Liakhovetskie0056b32008-08-31 00:39:47 +0200121/*
122 * This function is called before encoding ecc codes to ready ecc engine.
123 * Written by jsgood
124 */
125static void s3c_nand_enable_hwecc(struct mtd_info *mtd, int mode)
126{
127 u_long nfcont, nfconf;
128
129 /*
130 * The original driver used 4-bit ECC for "new" MLC chips, i.e., for
131 * those with non-zero ID[3][3:2], which anyway only holds for ST
132 * (Numonyx) chips
133 */
134 nfconf = readl(NFCONF) & ~NFCONF_ECC_4BIT;
135
136 writel(nfconf, NFCONF);
137
138 /* Initialize & unlock */
139 nfcont = readl(NFCONT);
140 nfcont |= NFCONT_INITECC;
141 nfcont &= ~NFCONT_MECCLOCK;
142
143 if (mode == NAND_ECC_WRITE)
144 nfcont |= NFCONT_ECC_ENC;
145 else if (mode == NAND_ECC_READ)
146 nfcont &= ~NFCONT_ECC_ENC;
147
148 writel(nfcont, NFCONT);
149}
150
151/*
152 * This function is called immediately after encoding ecc codes.
153 * This function returns encoded ecc codes.
154 * Written by jsgood
155 */
156static int s3c_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
157 u_char *ecc_code)
158{
159 u_long nfcont, nfmecc0;
160
161 /* Lock */
162 nfcont = readl(NFCONT);
163 nfcont |= NFCONT_MECCLOCK;
164 writel(nfcont, NFCONT);
165
166 nfmecc0 = readl(NFMECC0);
167
168 ecc_code[0] = nfmecc0 & 0xff;
169 ecc_code[1] = (nfmecc0 >> 8) & 0xff;
170 ecc_code[2] = (nfmecc0 >> 16) & 0xff;
171 ecc_code[3] = (nfmecc0 >> 24) & 0xff;
172
173 return 0;
174}
175
176/*
177 * This function determines whether read data is good or not.
178 * If SLC, must write ecc codes to controller before reading status bit.
179 * If MLC, status bit is already set, so only reading is needed.
180 * If status bit is good, return 0.
181 * If correctable errors occured, do that.
182 * If uncorrectable errors occured, return -1.
183 * Written by jsgood
184 */
185static int s3c_nand_correct_data(struct mtd_info *mtd, u_char *dat,
186 u_char *read_ecc, u_char *calc_ecc)
187{
188 int ret = -1;
189 u_long nfestat0, nfmeccdata0, nfmeccdata1, err_byte_addr;
190 u_char err_type, repaired;
191
192 /* SLC: Write ecc to compare */
193 nfmeccdata0 = (calc_ecc[1] << 16) | calc_ecc[0];
194 nfmeccdata1 = (calc_ecc[3] << 16) | calc_ecc[2];
195 writel(nfmeccdata0, NFMECCDATA0);
196 writel(nfmeccdata1, NFMECCDATA1);
197
198 /* Read ecc status */
199 nfestat0 = readl(NFESTAT0);
200 err_type = nfestat0 & 0x3;
201
202 switch (err_type) {
203 case 0: /* No error */
204 ret = 0;
205 break;
206
207 case 1:
208 /*
209 * 1 bit error (Correctable)
210 * (nfestat0 >> 7) & 0x7ff :error byte number
211 * (nfestat0 >> 4) & 0x7 :error bit number
212 */
213 err_byte_addr = (nfestat0 >> 7) & 0x7ff;
214 repaired = dat[err_byte_addr] ^ (1 << ((nfestat0 >> 4) & 0x7));
215
216 printf("S3C NAND: 1 bit error detected at byte %ld. "
217 "Correcting from 0x%02x to 0x%02x...OK\n",
218 err_byte_addr, dat[err_byte_addr], repaired);
219
220 dat[err_byte_addr] = repaired;
221
222 ret = 1;
223 break;
224
225 case 2: /* Multiple error */
226 case 3: /* ECC area error */
227 printf("S3C NAND: ECC uncorrectable error detected. "
228 "Not correctable.\n");
229 ret = -1;
230 break;
231 }
232
233 return ret;
234}
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200235#endif /* CONFIG_SYS_S3C_NAND_HWECC */
Guennadi Liakhovetskie0056b32008-08-31 00:39:47 +0200236
237/*
238 * Board-specific NAND initialization. The following members of the
239 * argument are board-specific (per include/linux/mtd/nand.h):
240 * - IO_ADDR_R?: address to read the 8 I/O lines of the flash device
241 * - IO_ADDR_W?: address to write the 8 I/O lines of the flash device
242 * - hwcontrol: hardwarespecific function for accesing control-lines
243 * - dev_ready: hardwarespecific function for accesing device ready/busy line
244 * - enable_hwecc?: function to enable (reset) hardware ecc generator. Must
245 * only be provided if a hardware ECC is available
246 * - eccmode: mode of ecc, see defines
247 * - chip_delay: chip dependent delay for transfering data from array to
248 * read regs (tR)
249 * - options: various chip options. They can partly be set to inform
250 * nand_scan about special functionality. See the defines for further
251 * explanation
252 * Members with a "?" were not set in the merged testing-NAND branch,
253 * so they are not set here either.
254 */
255int board_nand_init(struct nand_chip *nand)
256{
257 static int chip_n;
258
259 if (chip_n >= MAX_CHIPS)
260 return -ENODEV;
261
262 NFCONT_REG = (NFCONT_REG & ~NFCONT_WP) | NFCONT_ENABLE | 0x6;
263
264 nand->IO_ADDR_R = (void __iomem *)NFDATA;
265 nand->IO_ADDR_W = (void __iomem *)NFDATA;
266 nand->cmd_ctrl = s3c_nand_hwcontrol;
267 nand->dev_ready = s3c_nand_device_ready;
268 nand->select_chip = s3c_nand_select_chip;
269 nand->options = 0;
270#ifdef CONFIG_NAND_SPL
271 nand->read_byte = nand_read_byte;
272 nand->write_buf = nand_write_buf;
273 nand->read_buf = nand_read_buf;
274#endif
275
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200276#ifdef CONFIG_SYS_S3C_NAND_HWECC
Guennadi Liakhovetskie0056b32008-08-31 00:39:47 +0200277 nand->ecc.hwctl = s3c_nand_enable_hwecc;
278 nand->ecc.calculate = s3c_nand_calculate_ecc;
279 nand->ecc.correct = s3c_nand_correct_data;
280
281 /*
282 * If you get more than 1 NAND-chip with different page-sizes on the
283 * board one day, it will get more complicated...
284 */
285 nand->ecc.mode = NAND_ECC_HW;
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200286 nand->ecc.size = CONFIG_SYS_NAND_ECCSIZE;
287 nand->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES;
Guennadi Liakhovetskie0056b32008-08-31 00:39:47 +0200288#else
289 nand->ecc.mode = NAND_ECC_SOFT;
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200290#endif /* ! CONFIG_SYS_S3C_NAND_HWECC */
Guennadi Liakhovetskie0056b32008-08-31 00:39:47 +0200291
292 nand->priv = nand_cs + chip_n++;
293
294 return 0;
295}