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,
24 #include <asm/arch/s3c24x0_cpu.h>
27 #define S3C2410_NFCONF_EN (1<<15)
28 #define S3C2410_NFCONF_512BYTE (1<<14)
29 #define S3C2410_NFCONF_4STEP (1<<13)
30 #define S3C2410_NFCONF_INITECC (1<<12)
31 #define S3C2410_NFCONF_nFCE (1<<11)
32 #define S3C2410_NFCONF_TACLS(x) ((x)<<8)
33 #define S3C2410_NFCONF_TWRPH0(x) ((x)<<4)
34 #define S3C2410_NFCONF_TWRPH1(x) ((x)<<0)
36 #define S3C2410_ADDR_NALE 4
37 #define S3C2410_ADDR_NCLE 8
39 #ifdef CONFIG_NAND_SPL
41 /* in the early stage of NAND flash booting, printf() is not available */
42 #define printf(fmt, args...)
44 static void nand_read_buf(struct mtd_info
*mtd
, u_char
*buf
, int len
)
47 struct nand_chip
*this = mtd
->priv
;
49 for (i
= 0; i
< len
; i
++)
50 buf
[i
] = readb(this->IO_ADDR_R
);
54 static void s3c2410_hwcontrol(struct mtd_info
*mtd
, int cmd
, unsigned int ctrl
)
56 struct nand_chip
*chip
= mtd
->priv
;
57 struct s3c2410_nand
*nand
= s3c2410_get_base_nand();
59 debugX(1, "hwcontrol(): 0x%02x 0x%02x\n", cmd
, ctrl
);
61 if (ctrl
& NAND_CTRL_CHANGE
) {
62 ulong IO_ADDR_W
= (ulong
)nand
;
64 if (!(ctrl
& NAND_CLE
))
65 IO_ADDR_W
|= S3C2410_ADDR_NCLE
;
66 if (!(ctrl
& NAND_ALE
))
67 IO_ADDR_W
|= S3C2410_ADDR_NALE
;
69 chip
->IO_ADDR_W
= (void *)IO_ADDR_W
;
72 writel(readl(&nand
->nfconf
) & ~S3C2410_NFCONF_nFCE
,
75 writel(readl(&nand
->nfconf
) | S3C2410_NFCONF_nFCE
,
79 if (cmd
!= NAND_CMD_NONE
)
80 writeb(cmd
, chip
->IO_ADDR_W
);
83 static int s3c2410_dev_ready(struct mtd_info
*mtd
)
85 struct s3c2410_nand
*nand
= s3c2410_get_base_nand();
86 debugX(1, "dev_ready\n");
87 return readl(&nand
->nfstat
) & 0x01;
90 #ifdef CONFIG_S3C2410_NAND_HWECC
91 void s3c2410_nand_enable_hwecc(struct mtd_info
*mtd
, int mode
)
93 struct s3c2410_nand
*nand
= s3c2410_get_base_nand();
94 debugX(1, "s3c2410_nand_enable_hwecc(%p, %d)\n", mtd
, mode
);
95 writel(readl(&nand
->nfconf
) | S3C2410_NFCONF_INITECC
, &nand
->nfconf
);
98 static int s3c2410_nand_calculate_ecc(struct mtd_info
*mtd
, const u_char
*dat
,
101 struct s3c2410_nand
*nand
= s3c2410_get_base_nand();
102 ecc_code
[0] = readb(&nand
->nfecc
);
103 ecc_code
[1] = readb(&nand
->nfecc
+ 1);
104 ecc_code
[2] = readb(&nand
->nfecc
+ 2);
105 debugX(1, "s3c2410_nand_calculate_hwecc(%p,): 0x%02x 0x%02x 0x%02x\n",
106 mtd
, ecc_code
[0], ecc_code
[1], ecc_code
[2]);
111 static int s3c2410_nand_correct_data(struct mtd_info
*mtd
, u_char
*dat
,
112 u_char
*read_ecc
, u_char
*calc_ecc
)
114 if (read_ecc
[0] == calc_ecc
[0] &&
115 read_ecc
[1] == calc_ecc
[1] &&
116 read_ecc
[2] == calc_ecc
[2])
119 printf("s3c2410_nand_correct_data: not implemented\n");
124 int board_nand_init(struct nand_chip
*nand
)
127 u_int8_t tacls
, twrph0
, twrph1
;
128 struct s3c24x0_clock_power
*clk_power
= s3c24x0_get_base_clock_power();
129 struct s3c2410_nand
*nand_reg
= s3c2410_get_base_nand();
131 debugX(1, "board_nand_init()\n");
133 writel(readl(&clk_power
->clkcon
) | (1 << 4), &clk_power
->clkcon
);
135 /* initialize hardware */
136 #if defined(CONFIG_S3C24XX_CUSTOM_NAND_TIMING)
137 tacls
= CONFIG_S3C24XX_TACLS
;
138 twrph0
= CONFIG_S3C24XX_TWRPH0
;
139 twrph1
= CONFIG_S3C24XX_TWRPH1
;
146 cfg
= S3C2410_NFCONF_EN
;
147 cfg
|= S3C2410_NFCONF_TACLS(tacls
- 1);
148 cfg
|= S3C2410_NFCONF_TWRPH0(twrph0
- 1);
149 cfg
|= S3C2410_NFCONF_TWRPH1(twrph1
- 1);
150 writel(cfg
, &nand_reg
->nfconf
);
152 /* initialize nand_chip data structure */
153 nand
->IO_ADDR_R
= (void *)&nand_reg
->nfdata
;
154 nand
->IO_ADDR_W
= (void *)&nand_reg
->nfdata
;
156 nand
->select_chip
= NULL
;
158 /* read_buf and write_buf are default */
159 /* read_byte and write_byte are default */
160 #ifdef CONFIG_NAND_SPL
161 nand
->read_buf
= nand_read_buf
;
164 /* hwcontrol always must be implemented */
165 nand
->cmd_ctrl
= s3c2410_hwcontrol
;
167 nand
->dev_ready
= s3c2410_dev_ready
;
169 #ifdef CONFIG_S3C2410_NAND_HWECC
170 nand
->ecc
.hwctl
= s3c2410_nand_enable_hwecc
;
171 nand
->ecc
.calculate
= s3c2410_nand_calculate_ecc
;
172 nand
->ecc
.correct
= s3c2410_nand_correct_data
;
173 nand
->ecc
.mode
= NAND_ECC_HW
;
174 nand
->ecc
.size
= CONFIG_SYS_NAND_ECCSIZE
;
175 nand
->ecc
.bytes
= CONFIG_SYS_NAND_ECCBYTES
;
177 nand
->ecc
.mode
= NAND_ECC_SOFT
;
180 #ifdef CONFIG_S3C2410_NAND_BBT
181 nand
->options
= NAND_USE_FLASH_BBT
;
186 debugX(1, "end of nand_init\n");