]>
Commit | Line | Data |
---|---|---|
887e2ec9 SR |
1 | /* |
2 | * Overview: | |
3 | * Platform independend driver for NDFC (NanD Flash Controller) | |
5d841fac | 4 | * integrated into IBM/AMCC PPC4xx cores |
887e2ec9 | 5 | * |
5d841fac | 6 | * (C) Copyright 2006-2009 |
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> | |
887e2ec9 SR |
33 | #include <nand.h> |
34 | #include <linux/mtd/ndfc.h> | |
91da09cf | 35 | #include <linux/mtd/nand_ecc.h> |
887e2ec9 | 36 | #include <asm/processor.h> |
91da09cf | 37 | #include <asm/io.h> |
6f3dfc13 | 38 | #include <ppc4xx.h> |
887e2ec9 | 39 | |
3df2ece0 SR |
40 | /* |
41 | * We need to store the info, which chip-select (CS) is used for the | |
42 | * chip number. For example on Sequoia NAND chip #0 uses | |
43 | * CS #3. | |
44 | */ | |
45 | static int ndfc_cs[NDFC_MAX_BANKS]; | |
887e2ec9 | 46 | |
cfa460ad | 47 | static void ndfc_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) |
887e2ec9 | 48 | { |
5e1dae5c | 49 | struct nand_chip *this = mtd->priv; |
3df2ece0 | 50 | ulong base = (ulong) this->IO_ADDR_W & 0xffffff00; |
cfa460ad | 51 | |
3df2ece0 SR |
52 | if (cmd == NAND_CMD_NONE) |
53 | return; | |
887e2ec9 | 54 | |
3df2ece0 SR |
55 | if (ctrl & NAND_CLE) |
56 | out_8((u8 *)(base + NDFC_CMD), cmd & 0xFF); | |
57 | else | |
58 | out_8((u8 *)(base + NDFC_ALE), cmd & 0xFF); | |
887e2ec9 SR |
59 | } |
60 | ||
61 | static int ndfc_dev_ready(struct mtd_info *mtdinfo) | |
62 | { | |
511d0c72 | 63 | struct nand_chip *this = mtdinfo->priv; |
3df2ece0 | 64 | ulong base = (ulong) this->IO_ADDR_W & 0xffffff00; |
887e2ec9 | 65 | |
3df2ece0 | 66 | return (in_be32((u32 *)(base + NDFC_STAT)) & NDFC_STAT_IS_READY); |
887e2ec9 SR |
67 | } |
68 | ||
91da09cf SR |
69 | static void ndfc_enable_hwecc(struct mtd_info *mtdinfo, int mode) |
70 | { | |
71 | struct nand_chip *this = mtdinfo->priv; | |
3df2ece0 | 72 | ulong base = (ulong) this->IO_ADDR_W & 0xffffff00; |
91da09cf SR |
73 | u32 ccr; |
74 | ||
75 | ccr = in_be32((u32 *)(base + NDFC_CCR)); | |
76 | ccr |= NDFC_CCR_RESET_ECC; | |
77 | out_be32((u32 *)(base + NDFC_CCR), ccr); | |
78 | } | |
79 | ||
80 | static int ndfc_calculate_ecc(struct mtd_info *mtdinfo, | |
81 | const u_char *dat, u_char *ecc_code) | |
82 | { | |
83 | struct nand_chip *this = mtdinfo->priv; | |
3df2ece0 | 84 | ulong base = (ulong) this->IO_ADDR_W & 0xffffff00; |
91da09cf SR |
85 | u32 ecc; |
86 | u8 *p = (u8 *)&ecc; | |
87 | ||
88 | ecc = in_be32((u32 *)(base + NDFC_ECC)); | |
89 | ||
90 | /* The NDFC uses Smart Media (SMC) bytes order | |
91 | */ | |
68e74567 FK |
92 | ecc_code[0] = p[1]; |
93 | ecc_code[1] = p[2]; | |
91da09cf SR |
94 | ecc_code[2] = p[3]; |
95 | ||
96 | return 0; | |
97 | } | |
887e2ec9 SR |
98 | |
99 | /* | |
100 | * Speedups for buffer read/write/verify | |
101 | * | |
102 | * NDFC allows 32bit read/write of data. So we can speed up the buffer | |
103 | * functions. No further checking, as nand_base will always read/write | |
104 | * page aligned. | |
105 | */ | |
106 | static void ndfc_read_buf(struct mtd_info *mtdinfo, uint8_t *buf, int len) | |
107 | { | |
511d0c72 | 108 | struct nand_chip *this = mtdinfo->priv; |
3df2ece0 | 109 | ulong base = (ulong) this->IO_ADDR_W & 0xffffff00; |
887e2ec9 SR |
110 | uint32_t *p = (uint32_t *) buf; |
111 | ||
43a2b0e7 | 112 | for (;len > 0; len -= 4) |
91da09cf | 113 | *p++ = in_be32((u32 *)(base + NDFC_DATA)); |
887e2ec9 SR |
114 | } |
115 | ||
91da09cf SR |
116 | #ifndef CONFIG_NAND_SPL |
117 | /* | |
118 | * Don't use these speedup functions in NAND boot image, since the image | |
119 | * has to fit into 4kByte. | |
120 | */ | |
887e2ec9 SR |
121 | static void ndfc_write_buf(struct mtd_info *mtdinfo, const uint8_t *buf, int len) |
122 | { | |
511d0c72 | 123 | struct nand_chip *this = mtdinfo->priv; |
3df2ece0 | 124 | ulong base = (ulong) this->IO_ADDR_W & 0xffffff00; |
887e2ec9 SR |
125 | uint32_t *p = (uint32_t *) buf; |
126 | ||
43a2b0e7 | 127 | for (; len > 0; len -= 4) |
91da09cf | 128 | out_be32((u32 *)(base + NDFC_DATA), *p++); |
887e2ec9 SR |
129 | } |
130 | ||
131 | static int ndfc_verify_buf(struct mtd_info *mtdinfo, const uint8_t *buf, int len) | |
132 | { | |
511d0c72 | 133 | struct nand_chip *this = mtdinfo->priv; |
3df2ece0 | 134 | ulong base = (ulong) this->IO_ADDR_W & 0xffffff00; |
887e2ec9 SR |
135 | uint32_t *p = (uint32_t *) buf; |
136 | ||
43a2b0e7 | 137 | for (; len > 0; len -= 4) |
91da09cf | 138 | if (*p++ != in_be32((u32 *)(base + NDFC_DATA))) |
887e2ec9 SR |
139 | return -1; |
140 | ||
141 | return 0; | |
142 | } | |
143 | #endif /* #ifndef CONFIG_NAND_SPL */ | |
144 | ||
6d0f6bcf JCPV |
145 | #ifndef CONFIG_SYS_NAND_BCR |
146 | #define CONFIG_SYS_NAND_BCR 0x80002222 | |
52aef8f9 WO |
147 | #endif |
148 | ||
43a2b0e7 SR |
149 | void board_nand_select_device(struct nand_chip *nand, int chip) |
150 | { | |
7ade0c63 SR |
151 | /* |
152 | * Don't use "chip" to address the NAND device, | |
153 | * generate the cs from the address where it is encoded. | |
154 | */ | |
3df2ece0 SR |
155 | ulong base = (ulong)nand->IO_ADDR_W & 0xffffff00; |
156 | int cs = ndfc_cs[chip]; | |
43a2b0e7 SR |
157 | |
158 | /* Set NandFlash Core Configuration Register */ | |
91da09cf SR |
159 | /* 1 col x 2 rows */ |
160 | out_be32((u32 *)(base + NDFC_CCR), 0x00000000 | (cs << 24)); | |
6d0f6bcf | 161 | out_be32((u32 *)(base + NDFC_BCFG0 + (cs << 2)), CONFIG_SYS_NAND_BCR); |
43a2b0e7 SR |
162 | } |
163 | ||
c2b4b2e4 SR |
164 | static void ndfc_select_chip(struct mtd_info *mtd, int chip) |
165 | { | |
166 | /* | |
167 | * Nothing to do here! | |
168 | */ | |
169 | } | |
170 | ||
fa230445 | 171 | int board_nand_init(struct nand_chip *nand) |
887e2ec9 | 172 | { |
7ade0c63 | 173 | int cs = (ulong)nand->IO_ADDR_W & 0x00000003; |
3df2ece0 SR |
174 | ulong base = (ulong)nand->IO_ADDR_W & 0xffffff00; |
175 | static int chip = 0; | |
43a2b0e7 | 176 | |
3df2ece0 SR |
177 | /* |
178 | * Save chip-select for this chip # | |
179 | */ | |
180 | ndfc_cs[chip] = cs; | |
887e2ec9 | 181 | |
3df2ece0 SR |
182 | /* |
183 | * Select required NAND chip in NDFC | |
184 | */ | |
185 | board_nand_select_device(nand, chip); | |
186 | ||
187 | nand->IO_ADDR_R = (void __iomem *)(base + NDFC_DATA); | |
188 | nand->IO_ADDR_W = (void __iomem *)(base + NDFC_DATA); | |
189 | nand->cmd_ctrl = ndfc_hwcontrol; | |
190 | nand->chip_delay = 50; | |
191 | nand->read_buf = ndfc_read_buf; | |
192 | nand->dev_ready = ndfc_dev_ready; | |
5e1dae5c WJ |
193 | nand->ecc.correct = nand_correct_data; |
194 | nand->ecc.hwctl = ndfc_enable_hwecc; | |
195 | nand->ecc.calculate = ndfc_calculate_ecc; | |
196 | nand->ecc.mode = NAND_ECC_HW; | |
197 | nand->ecc.size = 256; | |
198 | nand->ecc.bytes = 3; | |
c2b4b2e4 | 199 | nand->select_chip = ndfc_select_chip; |
91da09cf | 200 | |
887e2ec9 SR |
201 | #ifndef CONFIG_NAND_SPL |
202 | nand->write_buf = ndfc_write_buf; | |
887e2ec9 SR |
203 | nand->verify_buf = ndfc_verify_buf; |
204 | #else | |
205 | /* | |
206 | * Setup EBC (CS0 only right now) | |
207 | */ | |
6f3dfc13 | 208 | mtebc(EBC0_CFG, 0xb8400000); |
887e2ec9 | 209 | |
d1c3b275 SR |
210 | mtebc(PB0CR, CONFIG_SYS_EBC_PB0CR); |
211 | mtebc(PB0AP, CONFIG_SYS_EBC_PB0AP); | |
887e2ec9 SR |
212 | #endif |
213 | ||
3df2ece0 | 214 | chip++; |
dbbd1257 | 215 | |
fa230445 | 216 | return 0; |
887e2ec9 | 217 | } |