]>
Commit | Line | Data |
---|---|---|
887e2ec9 SR |
1 | /* |
2 | * Overview: | |
3 | * Platform independend driver for NDFC (NanD Flash Controller) | |
4 | * integrated into EP440 cores | |
5 | * | |
91da09cf | 6 | * (C) Copyright 2006-2007 |
887e2ec9 SR |
7 | * Stefan Roese, DENX Software Engineering, sr@denx.de. |
8 | * | |
9 | * Based on original work by | |
10 | * Thomas Gleixner | |
11 | * Copyright 2006 IBM | |
12 | * | |
13 | * See file CREDITS for list of people who contributed to this | |
14 | * project. | |
15 | * | |
16 | * This program is free software; you can redistribute it and/or | |
17 | * modify it under the terms of the GNU General Public License as | |
18 | * published by the Free Software Foundation; either version 2 of | |
19 | * the License, or (at your option) any later version. | |
20 | * | |
21 | * This program is distributed in the hope that it will be useful, | |
22 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
23 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
24 | * GNU General Public License for more details. | |
25 | * | |
26 | * You should have received a copy of the GNU General Public License | |
27 | * along with this program; if not, write to the Free Software | |
28 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
29 | * MA 02111-1307 USA | |
30 | */ | |
31 | ||
32 | #include <common.h> | |
33 | ||
cc4a0cee | 34 | #if defined(CONFIG_CMD_NAND) && !defined(CONFIG_NAND_LEGACY) && \ |
2d658967 | 35 | (defined(CONFIG_440EP) || defined(CONFIG_440GR) || \ |
6f3dfc13 | 36 | defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \ |
2801b2d2 SR |
37 | defined(CONFIG_405EZ) || defined(CONFIG_405EX) || \ |
38 | defined(CONFIG_460EX) || defined(CONFIG_460GT)) | |
887e2ec9 SR |
39 | |
40 | #include <nand.h> | |
41 | #include <linux/mtd/ndfc.h> | |
91da09cf | 42 | #include <linux/mtd/nand_ecc.h> |
887e2ec9 | 43 | #include <asm/processor.h> |
91da09cf | 44 | #include <asm/io.h> |
6f3dfc13 | 45 | #include <ppc4xx.h> |
887e2ec9 | 46 | |
3df2ece0 SR |
47 | /* |
48 | * We need to store the info, which chip-select (CS) is used for the | |
49 | * chip number. For example on Sequoia NAND chip #0 uses | |
50 | * CS #3. | |
51 | */ | |
52 | static int ndfc_cs[NDFC_MAX_BANKS]; | |
887e2ec9 | 53 | |
cfa460ad | 54 | static void ndfc_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) |
887e2ec9 | 55 | { |
5e1dae5c | 56 | struct nand_chip *this = mtd->priv; |
3df2ece0 | 57 | ulong base = (ulong) this->IO_ADDR_W & 0xffffff00; |
cfa460ad | 58 | |
3df2ece0 SR |
59 | if (cmd == NAND_CMD_NONE) |
60 | return; | |
887e2ec9 | 61 | |
3df2ece0 SR |
62 | if (ctrl & NAND_CLE) |
63 | out_8((u8 *)(base + NDFC_CMD), cmd & 0xFF); | |
64 | else | |
65 | out_8((u8 *)(base + NDFC_ALE), cmd & 0xFF); | |
887e2ec9 SR |
66 | } |
67 | ||
68 | static int ndfc_dev_ready(struct mtd_info *mtdinfo) | |
69 | { | |
511d0c72 | 70 | struct nand_chip *this = mtdinfo->priv; |
3df2ece0 | 71 | ulong base = (ulong) this->IO_ADDR_W & 0xffffff00; |
887e2ec9 | 72 | |
3df2ece0 | 73 | return (in_be32((u32 *)(base + NDFC_STAT)) & NDFC_STAT_IS_READY); |
887e2ec9 SR |
74 | } |
75 | ||
91da09cf SR |
76 | static void ndfc_enable_hwecc(struct mtd_info *mtdinfo, int mode) |
77 | { | |
78 | struct nand_chip *this = mtdinfo->priv; | |
3df2ece0 | 79 | ulong base = (ulong) this->IO_ADDR_W & 0xffffff00; |
91da09cf SR |
80 | u32 ccr; |
81 | ||
82 | ccr = in_be32((u32 *)(base + NDFC_CCR)); | |
83 | ccr |= NDFC_CCR_RESET_ECC; | |
84 | out_be32((u32 *)(base + NDFC_CCR), ccr); | |
85 | } | |
86 | ||
87 | static int ndfc_calculate_ecc(struct mtd_info *mtdinfo, | |
88 | const u_char *dat, u_char *ecc_code) | |
89 | { | |
90 | struct nand_chip *this = mtdinfo->priv; | |
3df2ece0 | 91 | ulong base = (ulong) this->IO_ADDR_W & 0xffffff00; |
91da09cf SR |
92 | u32 ecc; |
93 | u8 *p = (u8 *)&ecc; | |
94 | ||
95 | ecc = in_be32((u32 *)(base + NDFC_ECC)); | |
96 | ||
97 | /* The NDFC uses Smart Media (SMC) bytes order | |
98 | */ | |
ff02f139 SR |
99 | ecc_code[0] = p[1]; |
100 | ecc_code[1] = p[2]; | |
91da09cf SR |
101 | ecc_code[2] = p[3]; |
102 | ||
103 | return 0; | |
104 | } | |
887e2ec9 SR |
105 | |
106 | /* | |
107 | * Speedups for buffer read/write/verify | |
108 | * | |
109 | * NDFC allows 32bit read/write of data. So we can speed up the buffer | |
110 | * functions. No further checking, as nand_base will always read/write | |
111 | * page aligned. | |
112 | */ | |
113 | static void ndfc_read_buf(struct mtd_info *mtdinfo, uint8_t *buf, int len) | |
114 | { | |
511d0c72 | 115 | struct nand_chip *this = mtdinfo->priv; |
3df2ece0 | 116 | ulong base = (ulong) this->IO_ADDR_W & 0xffffff00; |
887e2ec9 SR |
117 | uint32_t *p = (uint32_t *) buf; |
118 | ||
43a2b0e7 | 119 | for (;len > 0; len -= 4) |
91da09cf | 120 | *p++ = in_be32((u32 *)(base + NDFC_DATA)); |
887e2ec9 SR |
121 | } |
122 | ||
91da09cf SR |
123 | #ifndef CONFIG_NAND_SPL |
124 | /* | |
125 | * Don't use these speedup functions in NAND boot image, since the image | |
126 | * has to fit into 4kByte. | |
127 | */ | |
887e2ec9 SR |
128 | static void ndfc_write_buf(struct mtd_info *mtdinfo, const uint8_t *buf, int len) |
129 | { | |
511d0c72 | 130 | struct nand_chip *this = mtdinfo->priv; |
3df2ece0 | 131 | ulong base = (ulong) this->IO_ADDR_W & 0xffffff00; |
887e2ec9 SR |
132 | uint32_t *p = (uint32_t *) buf; |
133 | ||
43a2b0e7 | 134 | for (; len > 0; len -= 4) |
91da09cf | 135 | out_be32((u32 *)(base + NDFC_DATA), *p++); |
887e2ec9 SR |
136 | } |
137 | ||
138 | static int ndfc_verify_buf(struct mtd_info *mtdinfo, const uint8_t *buf, int len) | |
139 | { | |
511d0c72 | 140 | struct nand_chip *this = mtdinfo->priv; |
3df2ece0 | 141 | ulong base = (ulong) this->IO_ADDR_W & 0xffffff00; |
887e2ec9 SR |
142 | uint32_t *p = (uint32_t *) buf; |
143 | ||
43a2b0e7 | 144 | for (; len > 0; len -= 4) |
91da09cf | 145 | if (*p++ != in_be32((u32 *)(base + NDFC_DATA))) |
887e2ec9 SR |
146 | return -1; |
147 | ||
148 | return 0; | |
149 | } | |
150 | #endif /* #ifndef CONFIG_NAND_SPL */ | |
151 | ||
6d0f6bcf JCPV |
152 | #ifndef CONFIG_SYS_NAND_BCR |
153 | #define CONFIG_SYS_NAND_BCR 0x80002222 | |
52aef8f9 WO |
154 | #endif |
155 | ||
43a2b0e7 SR |
156 | void board_nand_select_device(struct nand_chip *nand, int chip) |
157 | { | |
7ade0c63 SR |
158 | /* |
159 | * Don't use "chip" to address the NAND device, | |
160 | * generate the cs from the address where it is encoded. | |
161 | */ | |
3df2ece0 SR |
162 | ulong base = (ulong)nand->IO_ADDR_W & 0xffffff00; |
163 | int cs = ndfc_cs[chip]; | |
43a2b0e7 SR |
164 | |
165 | /* Set NandFlash Core Configuration Register */ | |
91da09cf SR |
166 | /* 1 col x 2 rows */ |
167 | out_be32((u32 *)(base + NDFC_CCR), 0x00000000 | (cs << 24)); | |
6d0f6bcf | 168 | out_be32((u32 *)(base + NDFC_BCFG0 + (cs << 2)), CONFIG_SYS_NAND_BCR); |
43a2b0e7 SR |
169 | } |
170 | ||
c2b4b2e4 SR |
171 | static void ndfc_select_chip(struct mtd_info *mtd, int chip) |
172 | { | |
173 | /* | |
174 | * Nothing to do here! | |
175 | */ | |
176 | } | |
177 | ||
fa230445 | 178 | int board_nand_init(struct nand_chip *nand) |
887e2ec9 | 179 | { |
7ade0c63 | 180 | int cs = (ulong)nand->IO_ADDR_W & 0x00000003; |
3df2ece0 SR |
181 | ulong base = (ulong)nand->IO_ADDR_W & 0xffffff00; |
182 | static int chip = 0; | |
43a2b0e7 | 183 | |
3df2ece0 SR |
184 | /* |
185 | * Save chip-select for this chip # | |
186 | */ | |
187 | ndfc_cs[chip] = cs; | |
887e2ec9 | 188 | |
3df2ece0 SR |
189 | /* |
190 | * Select required NAND chip in NDFC | |
191 | */ | |
192 | board_nand_select_device(nand, chip); | |
193 | ||
194 | nand->IO_ADDR_R = (void __iomem *)(base + NDFC_DATA); | |
195 | nand->IO_ADDR_W = (void __iomem *)(base + NDFC_DATA); | |
196 | nand->cmd_ctrl = ndfc_hwcontrol; | |
197 | nand->chip_delay = 50; | |
198 | nand->read_buf = ndfc_read_buf; | |
199 | nand->dev_ready = ndfc_dev_ready; | |
5e1dae5c WJ |
200 | nand->ecc.correct = nand_correct_data; |
201 | nand->ecc.hwctl = ndfc_enable_hwecc; | |
202 | nand->ecc.calculate = ndfc_calculate_ecc; | |
203 | nand->ecc.mode = NAND_ECC_HW; | |
204 | nand->ecc.size = 256; | |
205 | nand->ecc.bytes = 3; | |
c2b4b2e4 | 206 | nand->select_chip = ndfc_select_chip; |
91da09cf | 207 | |
887e2ec9 SR |
208 | #ifndef CONFIG_NAND_SPL |
209 | nand->write_buf = ndfc_write_buf; | |
887e2ec9 SR |
210 | nand->verify_buf = ndfc_verify_buf; |
211 | #else | |
212 | /* | |
213 | * Setup EBC (CS0 only right now) | |
214 | */ | |
6f3dfc13 | 215 | mtebc(EBC0_CFG, 0xb8400000); |
887e2ec9 | 216 | |
6d0f6bcf JCPV |
217 | mtebc(pb0cr, CONFIG_SYS_EBC_PB0CR); |
218 | mtebc(pb0ap, CONFIG_SYS_EBC_PB0AP); | |
887e2ec9 SR |
219 | #endif |
220 | ||
3df2ece0 | 221 | chip++; |
dbbd1257 | 222 | |
fa230445 | 223 | return 0; |
887e2ec9 SR |
224 | } |
225 | ||
226 | #endif |