2 * (C) Copyright 2006 OpenMoko, Inc.
3 * Author: Harald Welte <laforge@openmoko.org>
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of
8 * the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
26 #define DEBUGN(x, args ...) {}
29 #if defined(CONFIG_CMD_NAND)
30 #if !defined(CFG_NAND_LEGACY)
34 #define __REGb(x) (*(volatile unsigned char *)(x))
35 #define __REGi(x) (*(volatile unsigned int *)(x))
37 //#define NF_BASE 0x4e000000
39 //#define NFCONF __REGi(NF_BASE + 0x0)
41 #if defined(CONFIG_S3C2410)
44 #define NFB_BASE S3C2410_NAND_BASE
50 #define NFECC0 __REGb(NF_BASE + 0x14)
51 #define NFECC1 __REGb(NF_BASE + 0x15)
52 #define NFECC2 __REGb(NF_BASE + 0x16)
53 #define NFCONF_nFCE (1<<11)
55 #define S3C2410_NFCONF_EN (1<<15)
56 #define S3C2410_NFCONF_512BYTE (1<<14)
57 #define S3C2410_NFCONF_4STEP (1<<13)
58 #define S3C2410_NFCONF_INITECC (1<<12)
59 #define S3C2410_NFCONF_TACLS(x) ((x)<<8)
60 #define S3C2410_NFCONF_TWRPH0(x) ((x)<<4)
61 #define S3C2410_NFCONF_TWRPH1(x) ((x)<<0)
63 #elif defined(CONFIG_S3C2440) || defined(CONFIG_S3C2442)
66 #define NF_BASE S3C2440_NAND_BASE
73 #define NFECC0 __REGb(NF_BASE + 0x14)
74 #define NFECC1 __REGb(NF_BASE + 0x15)
75 #define NFECC2 __REGb(NF_BASE + 0x16)
77 //#define NFCONT __REGi(NF_BASE + 0x04)
78 //#define NFMECC0 __REGi(NF_BASE + 0x2C)
79 #define NFCONF_nFCE (1<<1)
80 #define S3C2440_NFCONT_INITECC (1<<4)
81 #define S3C2440_NFCONT_MAINECCLOCK (1<<5)
82 #define nand_select() (NFCONT &= ~(1 << 1))
83 #define nand_deselect() (NFCONT |= (1 << 1))
84 #define nand_clear_RnB() (NFSTAT |= (1 << 2))
85 #define nand_detect_RB() { while(!(NFSTAT&(1<<2))); }
86 #define nand_wait() { while(!(NFSTAT & 0x4)); } /* RnB_TransDectect */
90 //#define NFCMD __REGb(NF_BASE + oNFCMD)
91 //#define NFADDR __REGb(NF_BASE + oNFADDR)
92 //#define NFDATA __REGb(NF_BASE + oNFDATA)
93 //#define NFSTAT __REGb(NF_BASE + oNFSTAT)
95 #if defined(CONFIG_HXD8)
96 static int hxd8_nand_dev_ready(struct mtd_info
*mtd
)
98 S3C24X0_GPIO
* const gpio
= S3C24X0_GetBase_GPIO();
99 u_int32_t val
= gpio
->GPCDAT
;
101 switch (nand_curr_device
) {
103 return (NFSTAT
& 0x01);
105 return ((val
>>6) & 0x01);
107 return ((val
>>7) & 0x01);
109 return ((val
>>5) & 0x01);
115 /* 4G Nand flash chip select function */
116 static void hxd8_nand_select_chip(struct nand_chip
*this, int chip
)
118 S3C24X0_GPIO
* const gpio
= S3C24X0_GetBase_GPIO();
121 gpio
->GPGDAT
&= ~(1 << 1);
123 gpio
->GPGDAT
|= (1 << 1);
126 gpio
->GPADAT
&= ~(1 << 15);
128 gpio
->GPADAT
|= (1 << 15);
131 gpio
->GPADAT
&= ~(1 << 16);
133 gpio
->GPADAT
|= (1 << 16);
136 gpio
->GPADAT
&= ~(1 << 14);
138 gpio
->GPADAT
|= (1 << 14);
140 /* UGLY: ew don't have mtd_info pointer, but know that
141 * s3c24xx hwcontrol function does not use it for CLRNCE */
143 this->hwcontrol(NULL
, NAND_CTL_CLRNCE
);
145 this->hwcontrol(NULL
, NAND_CTL_SETNCE
);
149 static void s3c2410_hwcontrol(struct mtd_info
*mtd
, int cmd
)
151 struct nand_chip
*chip
= mtd
->priv
;
153 DEBUGN("hwcontrol(): 0x%02x: ", cmd
);
156 case NAND_CTL_SETNCE
:
157 #if defined(CONFIG_S3C2410)
158 NFCONF
&= ~NFCONF_nFCE
;
159 #elif defined(CONFIG_S3C2440) || defined(CONFIG_S3C2442)
160 #ifdef CONFIG_S3C2440_NAND_HWECC
161 NFCONT
= (NFCONT
& ~((1 << 5) | NFCONF_nFCE
)) | S3C2440_NFCONT_INITECC
;
164 NFCONT
&= ~NFCONF_nFCE
;
167 DEBUGN("NFCONF=0x%08x\n", NFCONF
);
169 case NAND_CTL_CLRNCE
:
170 #if defined(CONFIG_S3C2410)
171 NFCONF
|= NFCONF_nFCE
;
172 #elif defined(CONFIG_S3C2440) || defined(CONFIG_S3C2442)
173 NFCONT
&= ~NFCONF_nFCE
;
175 DEBUGN("NFCONF=0x%08x\n", NFCONF
);
177 case NAND_CTL_SETALE
:
178 chip
->IO_ADDR_W
= NF_BASE
+ oNFADDR
;
181 case NAND_CTL_SETCLE
:
182 chip
->IO_ADDR_W
= NF_BASE
+ oNFCMD
;
186 chip
->IO_ADDR_W
= NF_BASE
+ oNFDATA
;
192 static int s3c2410_dev_ready(struct mtd_info
*mtd
)
194 DEBUGN("dev_ready\n");
195 return (NFSTAT
& 0x01);
198 #ifdef CONFIG_S3C2410_NAND_HWECC
199 void s3c2410_nand_enable_hwecc(struct mtd_info
*mtd
, int mode
)
201 DEBUGN("s3c2410_nand_enable_hwecc(%p, %d)\n", mtd
,mode
);
202 NFCONF
|= S3C2410_NFCONF_INITECC
;
205 static int s3c2410_nand_calculate_ecc(struct mtd_info
*mtd
, const u_char
*dat
,
208 ecc_code
[0] = NFECC0
;
209 ecc_code
[1] = NFECC1
;
210 ecc_code
[2] = NFECC2
;
211 DEBUGN("s3c2410_nand_calculate_hwecc(%p,): 0x%02x 0x%02x 0x%02x\n",
212 mtd
, ecc_code
[0], ecc_code
[1], ecc_code
[2]);
217 static int s3c2410_nand_correct_data(struct mtd_info
*mtd
, u_char
*dat
,
218 u_char
*read_ecc
, u_char
*calc_ecc
)
220 if (read_ecc
[0] == calc_ecc
[0] &&
221 read_ecc
[1] == calc_ecc
[1] &&
222 read_ecc
[2] == calc_ecc
[2])
225 printf("s3c2410_nand_correct_data: not implemented\n");
230 #ifdef CONFIG_S3C2440_NAND_HWECC
231 void s3c244x_nand_enable_hwecc(struct mtd_info
*mtd
, int mode
)
233 DEBUGN("s3c244x_nand_enable_hwecc(%p, %d)\n", mtd
,mode
);
234 NFCONT
= (NFCONT
& ~(1 << 5)) | S3C2440_NFCONT_INITECC
;
237 static int s3c244x_nand_calculate_ecc(struct mtd_info
*mtd
, const u_char
*dat
,
240 ecc_code
[0] = NFECC0
;
241 ecc_code
[1] = NFECC1
;
242 ecc_code
[2] = NFECC2
;
243 DEBUGN("s3c244x_nand_calculate_hwecc(%p,): 0x%02x 0x%02x 0x%02x\n",
244 mtd
, ecc_code
[0], ecc_code
[1], ecc_code
[2]);
249 static int s3c244x_nand_correct_data(struct mtd_info
*mtd
, u_char
*dat
,
250 u_char
*read_ecc
, u_char
*calc_ecc
)
252 if (read_ecc
[0] == calc_ecc
[0] &&
253 read_ecc
[1] == calc_ecc
[1] &&
254 read_ecc
[2] == calc_ecc
[2])
257 printf("s3c244x_nand_correct_data: not implemented\n");
262 int board_nand_init(void) __attribute__((weak
, alias("__board_nand_init")));
264 int __board_nand_init(struct nand_chip
*nand
)
267 u_int8_t tacls
, twrph0
, twrph1
;
268 S3C24X0_CLOCK_POWER
* const clk_power
= S3C24X0_GetBase_CLOCK_POWER();
270 DEBUGN("board_nand_init()\n");
272 clk_power
->CLKCON
|= (1 << 4);
274 /* initialize hardware */
275 twrph0
= 3; twrph1
= 0; tacls
= 0;
277 #if defined(CONFIG_S3C2410)
278 cfg
= S3C2410_NFCONF_EN
;
279 cfg
|= S3C2410_NFCONF_TACLS(tacls
- 1);
280 cfg
|= S3C2410_NFCONF_TWRPH0(twrph0
- 1);
281 cfg
|= S3C2410_NFCONF_TWRPH1(twrph1
- 1);
284 #elif defined(CONFIG_S3C2440) || defined(CONFIG_S3C2442)
285 twrph0
= 7; twrph1
= 7; tacls
= 7;
286 NFCONF
= (tacls
<<12)|(twrph0
<<8)|(twrph1
<<4)|(0<<0);
287 NFCONT
= (0<<13)|(0<<12)|(0<<10)|(0<<9)|(0<<8)|(1<<6)|(1<<5)|(1<<4)|(1<<1)|(1<<0);
290 /* initialize nand_chip data structure */
291 nand
->IO_ADDR_R
= nand
->IO_ADDR_W
= NF_BASE
+ oNFDATA
;
293 /* read_buf and write_buf are default */
294 /* read_byte and write_byte are default */
296 /* hwcontrol always must be implemented */
297 nand
->hwcontrol
= s3c2410_hwcontrol
;
299 nand
->dev_ready
= s3c2410_dev_ready
;
301 #ifdef CONFIG_S3C2410_NAND_HWECC
302 nand
->enable_hwecc
= s3c2410_nand_enable_hwecc
;
303 nand
->calculate_ecc
= s3c2410_nand_calculate_ecc
;
304 nand
->correct_data
= s3c2410_nand_correct_data
;
305 nand
->eccmode
= NAND_ECC_HW3_512
;
306 #elif CONFIG_S3C2440_NAND_HWECC
307 nand
->enable_hwecc
= s3c244x_nand_enable_hwecc
;
308 nand
->calculate_ecc
= s3c244x_nand_calculate_ecc
;
309 nand
->correct_data
= s3c244x_nand_correct_data
;
310 nand
->eccmode
= NAND_ECC_HW3_512
;
312 nand
->eccmode
= NAND_ECC_SOFT
;
315 #if defined(CONFIG_HXD8)
316 nand
->dev_ready
= hxd8_nand_dev_ready
;
317 nand
->select_chip
= hxd8_nand_select_chip
;
320 #ifdef CONFIG_S3C2410_NAND_BBT
321 nand
->options
= NAND_USE_FLASH_BBT
| NAND_DONT_CREATE_BBT
;
326 #if defined(CONFIG_S3C2440) || defined(CONFIG_S3C2442)
330 NFCMD = NAND_CMD_RESET;
331 { volatile int i; for (i = 0; i < 10; i ++); }
337 DEBUGN("end of nand_init\n");
343 #error "U-Boot legacy NAND support not available for S3C24xx"