diff options
Diffstat (limited to 'drivers/mtd/nand')
-rw-r--r-- | drivers/mtd/nand/Kconfig | 28 | ||||
-rw-r--r-- | drivers/mtd/nand/Makefile | 3 | ||||
-rw-r--r-- | drivers/mtd/nand/atmel_nand.c (renamed from drivers/mtd/nand/at91_nand.c) | 278 | ||||
-rw-r--r-- | drivers/mtd/nand/atmel_nand_ecc.h | 36 | ||||
-rw-r--r-- | drivers/mtd/nand/au1550nd.c | 4 | ||||
-rw-r--r-- | drivers/mtd/nand/autcpu12.c | 2 | ||||
-rw-r--r-- | drivers/mtd/nand/cafe_nand.c | 6 | ||||
-rw-r--r-- | drivers/mtd/nand/diskonchip.c | 4 | ||||
-rw-r--r-- | drivers/mtd/nand/edb7312.c | 2 | ||||
-rw-r--r-- | drivers/mtd/nand/excite_nandflash.c | 2 | ||||
-rw-r--r-- | drivers/mtd/nand/fsl_elbc_nand.c | 63 | ||||
-rw-r--r-- | drivers/mtd/nand/h1910.c | 2 | ||||
-rw-r--r-- | drivers/mtd/nand/nand_base.c | 87 | ||||
-rw-r--r-- | drivers/mtd/nand/nand_bbt.c | 2 | ||||
-rw-r--r-- | drivers/mtd/nand/nand_ecc.c | 2 | ||||
-rw-r--r-- | drivers/mtd/nand/nand_ids.c | 2 | ||||
-rw-r--r-- | drivers/mtd/nand/nandsim.c | 41 | ||||
-rw-r--r-- | drivers/mtd/nand/ppchameleonevb.c | 2 | ||||
-rw-r--r-- | drivers/mtd/nand/rtc_from4.c | 2 | ||||
-rw-r--r-- | drivers/mtd/nand/s3c2410.c | 168 | ||||
-rw-r--r-- | drivers/mtd/nand/sharpsl.c | 2 | ||||
-rw-r--r-- | drivers/mtd/nand/spia.c | 2 | ||||
-rw-r--r-- | drivers/mtd/nand/toto.c | 2 | ||||
-rw-r--r-- | drivers/mtd/nand/ts7250.c | 2 |
24 files changed, 512 insertions, 232 deletions
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 5076faf9ca66..71406e517857 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig | |||
@@ -1,5 +1,4 @@ | |||
1 | # drivers/mtd/nand/Kconfig | 1 | # drivers/mtd/nand/Kconfig |
2 | # $Id: Kconfig,v 1.35 2005/11/07 11:14:30 gleixner Exp $ | ||
3 | 2 | ||
4 | menuconfig MTD_NAND | 3 | menuconfig MTD_NAND |
5 | tristate "NAND Device Support" | 4 | tristate "NAND Device Support" |
@@ -272,22 +271,23 @@ config MTD_NAND_CS553X | |||
272 | 271 | ||
273 | If you say "m", the module will be called "cs553x_nand.ko". | 272 | If you say "m", the module will be called "cs553x_nand.ko". |
274 | 273 | ||
275 | config MTD_NAND_AT91 | 274 | config MTD_NAND_ATMEL |
276 | bool "Support for NAND Flash / SmartMedia on AT91" | 275 | tristate "Support for NAND Flash / SmartMedia on AT91 and AVR32" |
277 | depends on ARCH_AT91 | 276 | depends on ARCH_AT91 || AVR32 |
278 | help | 277 | help |
279 | Enables support for NAND Flash / Smart Media Card interface | 278 | Enables support for NAND Flash / Smart Media Card interface |
280 | on Atmel AT91 processors. | 279 | on Atmel AT91 and AVR32 processors. |
281 | choice | 280 | choice |
282 | prompt "ECC management for NAND Flash / SmartMedia on AT91" | 281 | prompt "ECC management for NAND Flash / SmartMedia on AT91 / AVR32" |
283 | depends on MTD_NAND_AT91 | 282 | depends on MTD_NAND_ATMEL |
284 | 283 | ||
285 | config MTD_NAND_AT91_ECC_HW | 284 | config MTD_NAND_ATMEL_ECC_HW |
286 | bool "Hardware ECC" | 285 | bool "Hardware ECC" |
287 | depends on ARCH_AT91SAM9263 || ARCH_AT91SAM9260 | 286 | depends on ARCH_AT91SAM9263 || ARCH_AT91SAM9260 || AVR32 |
288 | help | 287 | help |
289 | Uses hardware ECC provided by the at91sam9260/at91sam9263 chip | 288 | Use hardware ECC instead of software ECC when the chip |
290 | instead of software ECC. | 289 | supports it. |
290 | |||
291 | The hardware ECC controller is capable of single bit error | 291 | The hardware ECC controller is capable of single bit error |
292 | correction and 2-bit random detection per page. | 292 | correction and 2-bit random detection per page. |
293 | 293 | ||
@@ -297,16 +297,16 @@ config MTD_NAND_AT91_ECC_HW | |||
297 | 297 | ||
298 | If unsure, say Y | 298 | If unsure, say Y |
299 | 299 | ||
300 | config MTD_NAND_AT91_ECC_SOFT | 300 | config MTD_NAND_ATMEL_ECC_SOFT |
301 | bool "Software ECC" | 301 | bool "Software ECC" |
302 | help | 302 | help |
303 | Uses software ECC. | 303 | Use software ECC. |
304 | 304 | ||
305 | NB : hardware and software ECC schemes are incompatible. | 305 | NB : hardware and software ECC schemes are incompatible. |
306 | If you switch from one to another, you'll have to erase your | 306 | If you switch from one to another, you'll have to erase your |
307 | mtd partition. | 307 | mtd partition. |
308 | 308 | ||
309 | config MTD_NAND_AT91_ECC_NONE | 309 | config MTD_NAND_ATMEL_ECC_NONE |
310 | bool "No ECC (testing only, DANGEROUS)" | 310 | bool "No ECC (testing only, DANGEROUS)" |
311 | depends on DEBUG_KERNEL | 311 | depends on DEBUG_KERNEL |
312 | help | 312 | help |
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index a6e74a46992a..d772581de573 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile | |||
@@ -1,7 +1,6 @@ | |||
1 | # | 1 | # |
2 | # linux/drivers/nand/Makefile | 2 | # linux/drivers/nand/Makefile |
3 | # | 3 | # |
4 | # $Id: Makefile.common,v 1.15 2004/11/26 12:28:22 dedekind Exp $ | ||
5 | 4 | ||
6 | obj-$(CONFIG_MTD_NAND) += nand.o nand_ecc.o | 5 | obj-$(CONFIG_MTD_NAND) += nand.o nand_ecc.o |
7 | obj-$(CONFIG_MTD_NAND_IDS) += nand_ids.o | 6 | obj-$(CONFIG_MTD_NAND_IDS) += nand_ids.o |
@@ -24,7 +23,7 @@ obj-$(CONFIG_MTD_NAND_TS7250) += ts7250.o | |||
24 | obj-$(CONFIG_MTD_NAND_NANDSIM) += nandsim.o | 23 | obj-$(CONFIG_MTD_NAND_NANDSIM) += nandsim.o |
25 | obj-$(CONFIG_MTD_NAND_CS553X) += cs553x_nand.o | 24 | obj-$(CONFIG_MTD_NAND_CS553X) += cs553x_nand.o |
26 | obj-$(CONFIG_MTD_NAND_NDFC) += ndfc.o | 25 | obj-$(CONFIG_MTD_NAND_NDFC) += ndfc.o |
27 | obj-$(CONFIG_MTD_NAND_AT91) += at91_nand.o | 26 | obj-$(CONFIG_MTD_NAND_ATMEL) += atmel_nand.o |
28 | obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o | 27 | obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o |
29 | obj-$(CONFIG_MTD_NAND_BASLER_EXCITE) += excite_nandflash.o | 28 | obj-$(CONFIG_MTD_NAND_BASLER_EXCITE) += excite_nandflash.o |
30 | obj-$(CONFIG_MTD_NAND_PXA3xx) += pxa3xx_nand.o | 29 | obj-$(CONFIG_MTD_NAND_PXA3xx) += pxa3xx_nand.o |
diff --git a/drivers/mtd/nand/at91_nand.c b/drivers/mtd/nand/atmel_nand.c index 0adb287027a2..99aec46e2145 100644 --- a/drivers/mtd/nand/at91_nand.c +++ b/drivers/mtd/nand/atmel_nand.c | |||
@@ -1,6 +1,4 @@ | |||
1 | /* | 1 | /* |
2 | * drivers/mtd/nand/at91_nand.c | ||
3 | * | ||
4 | * Copyright (C) 2003 Rick Bronson | 2 | * Copyright (C) 2003 Rick Bronson |
5 | * | 3 | * |
6 | * Derived from drivers/mtd/nand/autcpu12.c | 4 | * Derived from drivers/mtd/nand/autcpu12.c |
@@ -31,20 +29,19 @@ | |||
31 | #include <linux/mtd/nand.h> | 29 | #include <linux/mtd/nand.h> |
32 | #include <linux/mtd/partitions.h> | 30 | #include <linux/mtd/partitions.h> |
33 | 31 | ||
34 | #include <asm/io.h> | 32 | #include <linux/gpio.h> |
35 | #include <asm/sizes.h> | 33 | #include <linux/io.h> |
36 | 34 | ||
37 | #include <asm/hardware.h> | ||
38 | #include <asm/arch/board.h> | 35 | #include <asm/arch/board.h> |
39 | #include <asm/arch/gpio.h> | 36 | #include <asm/arch/cpu.h> |
40 | 37 | ||
41 | #ifdef CONFIG_MTD_NAND_AT91_ECC_HW | 38 | #ifdef CONFIG_MTD_NAND_ATMEL_ECC_HW |
42 | #define hard_ecc 1 | 39 | #define hard_ecc 1 |
43 | #else | 40 | #else |
44 | #define hard_ecc 0 | 41 | #define hard_ecc 0 |
45 | #endif | 42 | #endif |
46 | 43 | ||
47 | #ifdef CONFIG_MTD_NAND_AT91_ECC_NONE | 44 | #ifdef CONFIG_MTD_NAND_ATMEL_ECC_NONE |
48 | #define no_ecc 1 | 45 | #define no_ecc 1 |
49 | #else | 46 | #else |
50 | #define no_ecc 0 | 47 | #define no_ecc 0 |
@@ -52,18 +49,18 @@ | |||
52 | 49 | ||
53 | /* Register access macros */ | 50 | /* Register access macros */ |
54 | #define ecc_readl(add, reg) \ | 51 | #define ecc_readl(add, reg) \ |
55 | __raw_readl(add + AT91_ECC_##reg) | 52 | __raw_readl(add + ATMEL_ECC_##reg) |
56 | #define ecc_writel(add, reg, value) \ | 53 | #define ecc_writel(add, reg, value) \ |
57 | __raw_writel((value), add + AT91_ECC_##reg) | 54 | __raw_writel((value), add + ATMEL_ECC_##reg) |
58 | 55 | ||
59 | #include <asm/arch/at91_ecc.h> /* AT91SAM9260/3 ECC registers */ | 56 | #include "atmel_nand_ecc.h" /* Hardware ECC registers */ |
60 | 57 | ||
61 | /* oob layout for large page size | 58 | /* oob layout for large page size |
62 | * bad block info is on bytes 0 and 1 | 59 | * bad block info is on bytes 0 and 1 |
63 | * the bytes have to be consecutives to avoid | 60 | * the bytes have to be consecutives to avoid |
64 | * several NAND_CMD_RNDOUT during read | 61 | * several NAND_CMD_RNDOUT during read |
65 | */ | 62 | */ |
66 | static struct nand_ecclayout at91_oobinfo_large = { | 63 | static struct nand_ecclayout atmel_oobinfo_large = { |
67 | .eccbytes = 4, | 64 | .eccbytes = 4, |
68 | .eccpos = {60, 61, 62, 63}, | 65 | .eccpos = {60, 61, 62, 63}, |
69 | .oobfree = { | 66 | .oobfree = { |
@@ -76,7 +73,7 @@ static struct nand_ecclayout at91_oobinfo_large = { | |||
76 | * the bytes have to be consecutives to avoid | 73 | * the bytes have to be consecutives to avoid |
77 | * several NAND_CMD_RNDOUT during read | 74 | * several NAND_CMD_RNDOUT during read |
78 | */ | 75 | */ |
79 | static struct nand_ecclayout at91_oobinfo_small = { | 76 | static struct nand_ecclayout atmel_oobinfo_small = { |
80 | .eccbytes = 4, | 77 | .eccbytes = 4, |
81 | .eccpos = {0, 1, 2, 3}, | 78 | .eccpos = {0, 1, 2, 3}, |
82 | .oobfree = { | 79 | .oobfree = { |
@@ -84,11 +81,11 @@ static struct nand_ecclayout at91_oobinfo_small = { | |||
84 | }, | 81 | }, |
85 | }; | 82 | }; |
86 | 83 | ||
87 | struct at91_nand_host { | 84 | struct atmel_nand_host { |
88 | struct nand_chip nand_chip; | 85 | struct nand_chip nand_chip; |
89 | struct mtd_info mtd; | 86 | struct mtd_info mtd; |
90 | void __iomem *io_base; | 87 | void __iomem *io_base; |
91 | struct at91_nand_data *board; | 88 | struct atmel_nand_data *board; |
92 | struct device *dev; | 89 | struct device *dev; |
93 | void __iomem *ecc; | 90 | void __iomem *ecc; |
94 | }; | 91 | }; |
@@ -96,34 +93,34 @@ struct at91_nand_host { | |||
96 | /* | 93 | /* |
97 | * Enable NAND. | 94 | * Enable NAND. |
98 | */ | 95 | */ |
99 | static void at91_nand_enable(struct at91_nand_host *host) | 96 | static void atmel_nand_enable(struct atmel_nand_host *host) |
100 | { | 97 | { |
101 | if (host->board->enable_pin) | 98 | if (host->board->enable_pin) |
102 | at91_set_gpio_value(host->board->enable_pin, 0); | 99 | gpio_set_value(host->board->enable_pin, 0); |
103 | } | 100 | } |
104 | 101 | ||
105 | /* | 102 | /* |
106 | * Disable NAND. | 103 | * Disable NAND. |
107 | */ | 104 | */ |
108 | static void at91_nand_disable(struct at91_nand_host *host) | 105 | static void atmel_nand_disable(struct atmel_nand_host *host) |
109 | { | 106 | { |
110 | if (host->board->enable_pin) | 107 | if (host->board->enable_pin) |
111 | at91_set_gpio_value(host->board->enable_pin, 1); | 108 | gpio_set_value(host->board->enable_pin, 1); |
112 | } | 109 | } |
113 | 110 | ||
114 | /* | 111 | /* |
115 | * Hardware specific access to control-lines | 112 | * Hardware specific access to control-lines |
116 | */ | 113 | */ |
117 | static void at91_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) | 114 | static void atmel_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) |
118 | { | 115 | { |
119 | struct nand_chip *nand_chip = mtd->priv; | 116 | struct nand_chip *nand_chip = mtd->priv; |
120 | struct at91_nand_host *host = nand_chip->priv; | 117 | struct atmel_nand_host *host = nand_chip->priv; |
121 | 118 | ||
122 | if (ctrl & NAND_CTRL_CHANGE) { | 119 | if (ctrl & NAND_CTRL_CHANGE) { |
123 | if (ctrl & NAND_NCE) | 120 | if (ctrl & NAND_NCE) |
124 | at91_nand_enable(host); | 121 | atmel_nand_enable(host); |
125 | else | 122 | else |
126 | at91_nand_disable(host); | 123 | atmel_nand_disable(host); |
127 | } | 124 | } |
128 | if (cmd == NAND_CMD_NONE) | 125 | if (cmd == NAND_CMD_NONE) |
129 | return; | 126 | return; |
@@ -137,18 +134,49 @@ static void at91_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) | |||
137 | /* | 134 | /* |
138 | * Read the Device Ready pin. | 135 | * Read the Device Ready pin. |
139 | */ | 136 | */ |
140 | static int at91_nand_device_ready(struct mtd_info *mtd) | 137 | static int atmel_nand_device_ready(struct mtd_info *mtd) |
141 | { | 138 | { |
142 | struct nand_chip *nand_chip = mtd->priv; | 139 | struct nand_chip *nand_chip = mtd->priv; |
143 | struct at91_nand_host *host = nand_chip->priv; | 140 | struct atmel_nand_host *host = nand_chip->priv; |
144 | 141 | ||
145 | return at91_get_gpio_value(host->board->rdy_pin); | 142 | return gpio_get_value(host->board->rdy_pin); |
143 | } | ||
144 | |||
145 | /* | ||
146 | * Minimal-overhead PIO for data access. | ||
147 | */ | ||
148 | static void atmel_read_buf(struct mtd_info *mtd, u8 *buf, int len) | ||
149 | { | ||
150 | struct nand_chip *nand_chip = mtd->priv; | ||
151 | |||
152 | __raw_readsb(nand_chip->IO_ADDR_R, buf, len); | ||
153 | } | ||
154 | |||
155 | static void atmel_read_buf16(struct mtd_info *mtd, u8 *buf, int len) | ||
156 | { | ||
157 | struct nand_chip *nand_chip = mtd->priv; | ||
158 | |||
159 | __raw_readsw(nand_chip->IO_ADDR_R, buf, len / 2); | ||
160 | } | ||
161 | |||
162 | static void atmel_write_buf(struct mtd_info *mtd, const u8 *buf, int len) | ||
163 | { | ||
164 | struct nand_chip *nand_chip = mtd->priv; | ||
165 | |||
166 | __raw_writesb(nand_chip->IO_ADDR_W, buf, len); | ||
167 | } | ||
168 | |||
169 | static void atmel_write_buf16(struct mtd_info *mtd, const u8 *buf, int len) | ||
170 | { | ||
171 | struct nand_chip *nand_chip = mtd->priv; | ||
172 | |||
173 | __raw_writesw(nand_chip->IO_ADDR_W, buf, len / 2); | ||
146 | } | 174 | } |
147 | 175 | ||
148 | /* | 176 | /* |
149 | * write oob for small pages | 177 | * write oob for small pages |
150 | */ | 178 | */ |
151 | static int at91_nand_write_oob_512(struct mtd_info *mtd, | 179 | static int atmel_nand_write_oob_512(struct mtd_info *mtd, |
152 | struct nand_chip *chip, int page) | 180 | struct nand_chip *chip, int page) |
153 | { | 181 | { |
154 | int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad; | 182 | int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad; |
@@ -176,7 +204,7 @@ static int at91_nand_write_oob_512(struct mtd_info *mtd, | |||
176 | /* | 204 | /* |
177 | * read oob for small pages | 205 | * read oob for small pages |
178 | */ | 206 | */ |
179 | static int at91_nand_read_oob_512(struct mtd_info *mtd, | 207 | static int atmel_nand_read_oob_512(struct mtd_info *mtd, |
180 | struct nand_chip *chip, int page, int sndcmd) | 208 | struct nand_chip *chip, int page, int sndcmd) |
181 | { | 209 | { |
182 | if (sndcmd) { | 210 | if (sndcmd) { |
@@ -196,11 +224,11 @@ static int at91_nand_read_oob_512(struct mtd_info *mtd, | |||
196 | * dat: raw data (unused) | 224 | * dat: raw data (unused) |
197 | * ecc_code: buffer for ECC | 225 | * ecc_code: buffer for ECC |
198 | */ | 226 | */ |
199 | static int at91_nand_calculate(struct mtd_info *mtd, | 227 | static int atmel_nand_calculate(struct mtd_info *mtd, |
200 | const u_char *dat, unsigned char *ecc_code) | 228 | const u_char *dat, unsigned char *ecc_code) |
201 | { | 229 | { |
202 | struct nand_chip *nand_chip = mtd->priv; | 230 | struct nand_chip *nand_chip = mtd->priv; |
203 | struct at91_nand_host *host = nand_chip->priv; | 231 | struct atmel_nand_host *host = nand_chip->priv; |
204 | uint32_t *eccpos = nand_chip->ecc.layout->eccpos; | 232 | uint32_t *eccpos = nand_chip->ecc.layout->eccpos; |
205 | unsigned int ecc_value; | 233 | unsigned int ecc_value; |
206 | 234 | ||
@@ -211,7 +239,7 @@ static int at91_nand_calculate(struct mtd_info *mtd, | |||
211 | ecc_code[eccpos[1]] = (ecc_value >> 8) & 0xFF; | 239 | ecc_code[eccpos[1]] = (ecc_value >> 8) & 0xFF; |
212 | 240 | ||
213 | /* get the last 2 ECC bytes */ | 241 | /* get the last 2 ECC bytes */ |
214 | ecc_value = ecc_readl(host->ecc, NPR) & AT91_ECC_NPARITY; | 242 | ecc_value = ecc_readl(host->ecc, NPR) & ATMEL_ECC_NPARITY; |
215 | 243 | ||
216 | ecc_code[eccpos[2]] = ecc_value & 0xFF; | 244 | ecc_code[eccpos[2]] = ecc_value & 0xFF; |
217 | ecc_code[eccpos[3]] = (ecc_value >> 8) & 0xFF; | 245 | ecc_code[eccpos[3]] = (ecc_value >> 8) & 0xFF; |
@@ -226,7 +254,7 @@ static int at91_nand_calculate(struct mtd_info *mtd, | |||
226 | * chip: nand chip info structure | 254 | * chip: nand chip info structure |
227 | * buf: buffer to store read data | 255 | * buf: buffer to store read data |
228 | */ | 256 | */ |
229 | static int at91_nand_read_page(struct mtd_info *mtd, | 257 | static int atmel_nand_read_page(struct mtd_info *mtd, |
230 | struct nand_chip *chip, uint8_t *buf) | 258 | struct nand_chip *chip, uint8_t *buf) |
231 | { | 259 | { |
232 | int eccsize = chip->ecc.size; | 260 | int eccsize = chip->ecc.size; |
@@ -237,6 +265,19 @@ static int at91_nand_read_page(struct mtd_info *mtd, | |||
237 | uint8_t *ecc_pos; | 265 | uint8_t *ecc_pos; |
238 | int stat; | 266 | int stat; |
239 | 267 | ||
268 | /* | ||
269 | * Errata: ALE is incorrectly wired up to the ECC controller | ||
270 | * on the AP7000, so it will include the address cycles in the | ||
271 | * ECC calculation. | ||
272 | * | ||
273 | * Workaround: Reset the parity registers before reading the | ||
274 | * actual data. | ||
275 | */ | ||
276 | if (cpu_is_at32ap7000()) { | ||
277 | struct atmel_nand_host *host = chip->priv; | ||
278 | ecc_writel(host->ecc, CR, ATMEL_ECC_RST); | ||
279 | } | ||
280 | |||
240 | /* read the page */ | 281 | /* read the page */ |
241 | chip->read_buf(mtd, p, eccsize); | 282 | chip->read_buf(mtd, p, eccsize); |
242 | 283 | ||
@@ -285,11 +326,11 @@ static int at91_nand_read_page(struct mtd_info *mtd, | |||
285 | * | 326 | * |
286 | * Detect and correct a 1 bit error for a page | 327 | * Detect and correct a 1 bit error for a page |
287 | */ | 328 | */ |
288 | static int at91_nand_correct(struct mtd_info *mtd, u_char *dat, | 329 | static int atmel_nand_correct(struct mtd_info *mtd, u_char *dat, |
289 | u_char *read_ecc, u_char *isnull) | 330 | u_char *read_ecc, u_char *isnull) |
290 | { | 331 | { |
291 | struct nand_chip *nand_chip = mtd->priv; | 332 | struct nand_chip *nand_chip = mtd->priv; |
292 | struct at91_nand_host *host = nand_chip->priv; | 333 | struct atmel_nand_host *host = nand_chip->priv; |
293 | unsigned int ecc_status; | 334 | unsigned int ecc_status; |
294 | unsigned int ecc_word, ecc_bit; | 335 | unsigned int ecc_word, ecc_bit; |
295 | 336 | ||
@@ -297,43 +338,43 @@ static int at91_nand_correct(struct mtd_info *mtd, u_char *dat, | |||
297 | ecc_status = ecc_readl(host->ecc, SR); | 338 | ecc_status = ecc_readl(host->ecc, SR); |
298 | 339 | ||
299 | /* if there's no error */ | 340 | /* if there's no error */ |
300 | if (likely(!(ecc_status & AT91_ECC_RECERR))) | 341 | if (likely(!(ecc_status & ATMEL_ECC_RECERR))) |
301 | return 0; | 342 | return 0; |
302 | 343 | ||
303 | /* get error bit offset (4 bits) */ | 344 | /* get error bit offset (4 bits) */ |
304 | ecc_bit = ecc_readl(host->ecc, PR) & AT91_ECC_BITADDR; | 345 | ecc_bit = ecc_readl(host->ecc, PR) & ATMEL_ECC_BITADDR; |
305 | /* get word address (12 bits) */ | 346 | /* get word address (12 bits) */ |
306 | ecc_word = ecc_readl(host->ecc, PR) & AT91_ECC_WORDADDR; | 347 | ecc_word = ecc_readl(host->ecc, PR) & ATMEL_ECC_WORDADDR; |
307 | ecc_word >>= 4; | 348 | ecc_word >>= 4; |
308 | 349 | ||
309 | /* if there are multiple errors */ | 350 | /* if there are multiple errors */ |
310 | if (ecc_status & AT91_ECC_MULERR) { | 351 | if (ecc_status & ATMEL_ECC_MULERR) { |
311 | /* check if it is a freshly erased block | 352 | /* check if it is a freshly erased block |
312 | * (filled with 0xff) */ | 353 | * (filled with 0xff) */ |
313 | if ((ecc_bit == AT91_ECC_BITADDR) | 354 | if ((ecc_bit == ATMEL_ECC_BITADDR) |
314 | && (ecc_word == (AT91_ECC_WORDADDR >> 4))) { | 355 | && (ecc_word == (ATMEL_ECC_WORDADDR >> 4))) { |
315 | /* the block has just been erased, return OK */ | 356 | /* the block has just been erased, return OK */ |
316 | return 0; | 357 | return 0; |
317 | } | 358 | } |
318 | /* it doesn't seems to be a freshly | 359 | /* it doesn't seems to be a freshly |
319 | * erased block. | 360 | * erased block. |
320 | * We can't correct so many errors */ | 361 | * We can't correct so many errors */ |
321 | dev_dbg(host->dev, "at91_nand : multiple errors detected." | 362 | dev_dbg(host->dev, "atmel_nand : multiple errors detected." |
322 | " Unable to correct.\n"); | 363 | " Unable to correct.\n"); |
323 | return -EIO; | 364 | return -EIO; |
324 | } | 365 | } |
325 | 366 | ||
326 | /* if there's a single bit error : we can correct it */ | 367 | /* if there's a single bit error : we can correct it */ |
327 | if (ecc_status & AT91_ECC_ECCERR) { | 368 | if (ecc_status & ATMEL_ECC_ECCERR) { |
328 | /* there's nothing much to do here. | 369 | /* there's nothing much to do here. |
329 | * the bit error is on the ECC itself. | 370 | * the bit error is on the ECC itself. |
330 | */ | 371 | */ |
331 | dev_dbg(host->dev, "at91_nand : one bit error on ECC code." | 372 | dev_dbg(host->dev, "atmel_nand : one bit error on ECC code." |
332 | " Nothing to correct\n"); | 373 | " Nothing to correct\n"); |
333 | return 0; | 374 | return 0; |
334 | } | 375 | } |
335 | 376 | ||
336 | dev_dbg(host->dev, "at91_nand : one bit error on data." | 377 | dev_dbg(host->dev, "atmel_nand : one bit error on data." |
337 | " (word offset in the page :" | 378 | " (word offset in the page :" |
338 | " 0x%x bit offset : 0x%x)\n", | 379 | " 0x%x bit offset : 0x%x)\n", |
339 | ecc_word, ecc_bit); | 380 | ecc_word, ecc_bit); |
@@ -345,14 +386,21 @@ static int at91_nand_correct(struct mtd_info *mtd, u_char *dat, | |||
345 | /* 8 bits words */ | 386 | /* 8 bits words */ |
346 | dat[ecc_word] ^= (1 << ecc_bit); | 387 | dat[ecc_word] ^= (1 << ecc_bit); |
347 | } | 388 | } |
348 | dev_dbg(host->dev, "at91_nand : error corrected\n"); | 389 | dev_dbg(host->dev, "atmel_nand : error corrected\n"); |
349 | return 1; | 390 | return 1; |
350 | } | 391 | } |
351 | 392 | ||
352 | /* | 393 | /* |
353 | * Enable HW ECC : unsused | 394 | * Enable HW ECC : unused on most chips |
354 | */ | 395 | */ |
355 | static void at91_nand_hwctl(struct mtd_info *mtd, int mode) { ; } | 396 | static void atmel_nand_hwctl(struct mtd_info *mtd, int mode) |
397 | { | ||
398 | if (cpu_is_at32ap7000()) { | ||
399 | struct nand_chip *nand_chip = mtd->priv; | ||
400 | struct atmel_nand_host *host = nand_chip->priv; | ||
401 | ecc_writel(host->ecc, CR, ATMEL_ECC_RST); | ||
402 | } | ||
403 | } | ||
356 | 404 | ||
357 | #ifdef CONFIG_MTD_PARTITIONS | 405 | #ifdef CONFIG_MTD_PARTITIONS |
358 | static const char *part_probes[] = { "cmdlinepart", NULL }; | 406 | static const char *part_probes[] = { "cmdlinepart", NULL }; |
@@ -361,9 +409,9 @@ static const char *part_probes[] = { "cmdlinepart", NULL }; | |||
361 | /* | 409 | /* |
362 | * Probe for the NAND device. | 410 | * Probe for the NAND device. |
363 | */ | 411 | */ |
364 | static int __init at91_nand_probe(struct platform_device *pdev) | 412 | static int __init atmel_nand_probe(struct platform_device *pdev) |
365 | { | 413 | { |
366 | struct at91_nand_host *host; | 414 | struct atmel_nand_host *host; |
367 | struct mtd_info *mtd; | 415 | struct mtd_info *mtd; |
368 | struct nand_chip *nand_chip; | 416 | struct nand_chip *nand_chip; |
369 | struct resource *regs; | 417 | struct resource *regs; |
@@ -375,24 +423,24 @@ static int __init at91_nand_probe(struct platform_device *pdev) | |||
375 | int num_partitions = 0; | 423 | int num_partitions = 0; |
376 | #endif | 424 | #endif |
377 | 425 | ||
378 | /* Allocate memory for the device structure (and zero it) */ | ||
379 | host = kzalloc(sizeof(struct at91_nand_host), GFP_KERNEL); | ||
380 | if (!host) { | ||
381 | printk(KERN_ERR "at91_nand: failed to allocate device structure.\n"); | ||
382 | return -ENOMEM; | ||
383 | } | ||
384 | |||
385 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 426 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
386 | if (!mem) { | 427 | if (!mem) { |
387 | printk(KERN_ERR "at91_nand: can't get I/O resource mem\n"); | 428 | printk(KERN_ERR "atmel_nand: can't get I/O resource mem\n"); |
388 | return -ENXIO; | 429 | return -ENXIO; |
389 | } | 430 | } |
390 | 431 | ||
432 | /* Allocate memory for the device structure (and zero it) */ | ||
433 | host = kzalloc(sizeof(struct atmel_nand_host), GFP_KERNEL); | ||
434 | if (!host) { | ||
435 | printk(KERN_ERR "atmel_nand: failed to allocate device structure.\n"); | ||
436 | return -ENOMEM; | ||
437 | } | ||
438 | |||
391 | host->io_base = ioremap(mem->start, mem->end - mem->start + 1); | 439 | host->io_base = ioremap(mem->start, mem->end - mem->start + 1); |
392 | if (host->io_base == NULL) { | 440 | if (host->io_base == NULL) { |
393 | printk(KERN_ERR "at91_nand: ioremap failed\n"); | 441 | printk(KERN_ERR "atmel_nand: ioremap failed\n"); |
394 | kfree(host); | 442 | res = -EIO; |
395 | return -EIO; | 443 | goto err_nand_ioremap; |
396 | } | 444 | } |
397 | 445 | ||
398 | mtd = &host->mtd; | 446 | mtd = &host->mtd; |
@@ -407,14 +455,14 @@ static int __init at91_nand_probe(struct platform_device *pdev) | |||
407 | /* Set address of NAND IO lines */ | 455 | /* Set address of NAND IO lines */ |
408 | nand_chip->IO_ADDR_R = host->io_base; | 456 | nand_chip->IO_ADDR_R = host->io_base; |
409 | nand_chip->IO_ADDR_W = host->io_base; | 457 | nand_chip->IO_ADDR_W = host->io_base; |
410 | nand_chip->cmd_ctrl = at91_nand_cmd_ctrl; | 458 | nand_chip->cmd_ctrl = atmel_nand_cmd_ctrl; |
411 | 459 | ||
412 | if (host->board->rdy_pin) | 460 | if (host->board->rdy_pin) |
413 | nand_chip->dev_ready = at91_nand_device_ready; | 461 | nand_chip->dev_ready = atmel_nand_device_ready; |
414 | 462 | ||
415 | regs = platform_get_resource(pdev, IORESOURCE_MEM, 1); | 463 | regs = platform_get_resource(pdev, IORESOURCE_MEM, 1); |
416 | if (!regs && hard_ecc) { | 464 | if (!regs && hard_ecc) { |
417 | printk(KERN_ERR "at91_nand: can't get I/O resource " | 465 | printk(KERN_ERR "atmel_nand: can't get I/O resource " |
418 | "regs\nFalling back on software ECC\n"); | 466 | "regs\nFalling back on software ECC\n"); |
419 | } | 467 | } |
420 | 468 | ||
@@ -424,15 +472,15 @@ static int __init at91_nand_probe(struct platform_device *pdev) | |||
424 | if (hard_ecc && regs) { | 472 | if (hard_ecc && regs) { |
425 | host->ecc = ioremap(regs->start, regs->end - regs->start + 1); | 473 | host->ecc = ioremap(regs->start, regs->end - regs->start + 1); |
426 | if (host->ecc == NULL) { | 474 | if (host->ecc == NULL) { |
427 | printk(KERN_ERR "at91_nand: ioremap failed\n"); | 475 | printk(KERN_ERR "atmel_nand: ioremap failed\n"); |
428 | res = -EIO; | 476 | res = -EIO; |
429 | goto err_ecc_ioremap; | 477 | goto err_ecc_ioremap; |
430 | } | 478 | } |
431 | nand_chip->ecc.mode = NAND_ECC_HW_SYNDROME; | 479 | nand_chip->ecc.mode = NAND_ECC_HW_SYNDROME; |
432 | nand_chip->ecc.calculate = at91_nand_calculate; | 480 | nand_chip->ecc.calculate = atmel_nand_calculate; |
433 | nand_chip->ecc.correct = at91_nand_correct; | 481 | nand_chip->ecc.correct = atmel_nand_correct; |
434 | nand_chip->ecc.hwctl = at91_nand_hwctl; | 482 | nand_chip->ecc.hwctl = atmel_nand_hwctl; |
435 | nand_chip->ecc.read_page = at91_nand_read_page; | 483 | nand_chip->ecc.read_page = atmel_nand_read_page; |
436 | nand_chip->ecc.bytes = 4; | 484 | nand_chip->ecc.bytes = 4; |
437 | nand_chip->ecc.prepad = 0; | 485 | nand_chip->ecc.prepad = 0; |
438 | nand_chip->ecc.postpad = 0; | 486 | nand_chip->ecc.postpad = 0; |
@@ -440,24 +488,30 @@ static int __init at91_nand_probe(struct platform_device *pdev) | |||
440 | 488 | ||
441 | nand_chip->chip_delay = 20; /* 20us command delay time */ | 489 | nand_chip->chip_delay = 20; /* 20us command delay time */ |
442 | 490 | ||
443 | if (host->board->bus_width_16) /* 16-bit bus width */ | 491 | if (host->board->bus_width_16) { /* 16-bit bus width */ |
444 | nand_chip->options |= NAND_BUSWIDTH_16; | 492 | nand_chip->options |= NAND_BUSWIDTH_16; |
493 | nand_chip->read_buf = atmel_read_buf16; | ||
494 | nand_chip->write_buf = atmel_write_buf16; | ||
495 | } else { | ||
496 | nand_chip->read_buf = atmel_read_buf; | ||
497 | nand_chip->write_buf = atmel_write_buf; | ||
498 | } | ||
445 | 499 | ||
446 | platform_set_drvdata(pdev, host); | 500 | platform_set_drvdata(pdev, host); |
447 | at91_nand_enable(host); | 501 | atmel_nand_enable(host); |
448 | 502 | ||
449 | if (host->board->det_pin) { | 503 | if (host->board->det_pin) { |
450 | if (at91_get_gpio_value(host->board->det_pin)) { | 504 | if (gpio_get_value(host->board->det_pin)) { |
451 | printk ("No SmartMedia card inserted.\n"); | 505 | printk("No SmartMedia card inserted.\n"); |
452 | res = ENXIO; | 506 | res = ENXIO; |
453 | goto out; | 507 | goto err_no_card; |
454 | } | 508 | } |
455 | } | 509 | } |
456 | 510 | ||
457 | /* first scan to find the device and get the page size */ | 511 | /* first scan to find the device and get the page size */ |
458 | if (nand_scan_ident(mtd, 1)) { | 512 | if (nand_scan_ident(mtd, 1)) { |
459 | res = -ENXIO; | 513 | res = -ENXIO; |
460 | goto out; | 514 | goto err_scan_ident; |
461 | } | 515 | } |
462 | 516 | ||
463 | if (nand_chip->ecc.mode == NAND_ECC_HW_SYNDROME) { | 517 | if (nand_chip->ecc.mode == NAND_ECC_HW_SYNDROME) { |
@@ -467,22 +521,22 @@ static int __init at91_nand_probe(struct platform_device *pdev) | |||
467 | /* set ECC page size and oob layout */ | 521 | /* set ECC page size and oob layout */ |
468 | switch (mtd->writesize) { | 522 | switch (mtd->writesize) { |
469 | case 512: | 523 | case 512: |
470 | nand_chip->ecc.layout = &at91_oobinfo_small; | 524 | nand_chip->ecc.layout = &atmel_oobinfo_small; |
471 | nand_chip->ecc.read_oob = at91_nand_read_oob_512; | 525 | nand_chip->ecc.read_oob = atmel_nand_read_oob_512; |
472 | nand_chip->ecc.write_oob = at91_nand_write_oob_512; | 526 | nand_chip->ecc.write_oob = atmel_nand_write_oob_512; |
473 | ecc_writel(host->ecc, MR, AT91_ECC_PAGESIZE_528); | 527 | ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_528); |
474 | break; | 528 | break; |
475 | case 1024: | 529 | case 1024: |
476 | nand_chip->ecc.layout = &at91_oobinfo_large; | 530 | nand_chip->ecc.layout = &atmel_oobinfo_large; |
477 | ecc_writel(host->ecc, MR, AT91_ECC_PAGESIZE_1056); | 531 | ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_1056); |
478 | break; | 532 | break; |
479 | case 2048: | 533 | case 2048: |
480 | nand_chip->ecc.layout = &at91_oobinfo_large; | 534 | nand_chip->ecc.layout = &atmel_oobinfo_large; |
481 | ecc_writel(host->ecc, MR, AT91_ECC_PAGESIZE_2112); | 535 | ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_2112); |
482 | break; | 536 | break; |
483 | case 4096: | 537 | case 4096: |
484 | nand_chip->ecc.layout = &at91_oobinfo_large; | 538 | nand_chip->ecc.layout = &atmel_oobinfo_large; |
485 | ecc_writel(host->ecc, MR, AT91_ECC_PAGESIZE_4224); | 539 | ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_4224); |
486 | break; | 540 | break; |
487 | default: | 541 | default: |
488 | /* page size not handled by HW ECC */ | 542 | /* page size not handled by HW ECC */ |
@@ -502,12 +556,12 @@ static int __init at91_nand_probe(struct platform_device *pdev) | |||
502 | /* second phase scan */ | 556 | /* second phase scan */ |
503 | if (nand_scan_tail(mtd)) { | 557 | if (nand_scan_tail(mtd)) { |
504 | res = -ENXIO; | 558 | res = -ENXIO; |
505 | goto out; | 559 | goto err_scan_tail; |
506 | } | 560 | } |
507 | 561 | ||
508 | #ifdef CONFIG_MTD_PARTITIONS | 562 | #ifdef CONFIG_MTD_PARTITIONS |
509 | #ifdef CONFIG_MTD_CMDLINE_PARTS | 563 | #ifdef CONFIG_MTD_CMDLINE_PARTS |
510 | mtd->name = "at91_nand"; | 564 | mtd->name = "atmel_nand"; |
511 | num_partitions = parse_mtd_partitions(mtd, part_probes, | 565 | num_partitions = parse_mtd_partitions(mtd, part_probes, |
512 | &partitions, 0); | 566 | &partitions, 0); |
513 | #endif | 567 | #endif |
@@ -516,9 +570,9 @@ static int __init at91_nand_probe(struct platform_device *pdev) | |||
516 | &num_partitions); | 570 | &num_partitions); |
517 | 571 | ||
518 | if ((!partitions) || (num_partitions == 0)) { | 572 | if ((!partitions) || (num_partitions == 0)) { |
519 | printk(KERN_ERR "at91_nand: No parititions defined, or unsupported device.\n"); | 573 | printk(KERN_ERR "atmel_nand: No parititions defined, or unsupported device.\n"); |
520 | res = ENXIO; | 574 | res = ENXIO; |
521 | goto release; | 575 | goto err_no_partitions; |
522 | } | 576 | } |
523 | 577 | ||
524 | res = add_mtd_partitions(mtd, partitions, num_partitions); | 578 | res = add_mtd_partitions(mtd, partitions, num_partitions); |
@@ -530,17 +584,19 @@ static int __init at91_nand_probe(struct platform_device *pdev) | |||
530 | return res; | 584 | return res; |
531 | 585 | ||
532 | #ifdef CONFIG_MTD_PARTITIONS | 586 | #ifdef CONFIG_MTD_PARTITIONS |
533 | release: | 587 | err_no_partitions: |
534 | #endif | 588 | #endif |
535 | nand_release(mtd); | 589 | nand_release(mtd); |
536 | 590 | err_scan_tail: | |
537 | out: | 591 | err_scan_ident: |
538 | iounmap(host->ecc); | 592 | err_no_card: |
539 | 593 | atmel_nand_disable(host); | |
540 | err_ecc_ioremap: | ||
541 | at91_nand_disable(host); | ||
542 | platform_set_drvdata(pdev, NULL); | 594 | platform_set_drvdata(pdev, NULL); |
595 | if (host->ecc) | ||
596 | iounmap(host->ecc); | ||
597 | err_ecc_ioremap: | ||
543 | iounmap(host->io_base); | 598 | iounmap(host->io_base); |
599 | err_nand_ioremap: | ||
544 | kfree(host); | 600 | kfree(host); |
545 | return res; | 601 | return res; |
546 | } | 602 | } |
@@ -548,47 +604,47 @@ err_ecc_ioremap: | |||
548 | /* | 604 | /* |
549 | * Remove a NAND device. | 605 | * Remove a NAND device. |
550 | */ | 606 | */ |
551 | static int __devexit at91_nand_remove(struct platform_device *pdev) | 607 | static int __exit atmel_nand_remove(struct platform_device *pdev) |
552 | { | 608 | { |
553 | struct at91_nand_host *host = platform_get_drvdata(pdev); | 609 | struct atmel_nand_host *host = platform_get_drvdata(pdev); |
554 | struct mtd_info *mtd = &host->mtd; | 610 | struct mtd_info *mtd = &host->mtd; |
555 | 611 | ||
556 | nand_release(mtd); | 612 | nand_release(mtd); |
557 | 613 | ||
558 | at91_nand_disable(host); | 614 | atmel_nand_disable(host); |
559 | 615 | ||
616 | if (host->ecc) | ||
617 | iounmap(host->ecc); | ||
560 | iounmap(host->io_base); | 618 | iounmap(host->io_base); |
561 | iounmap(host->ecc); | ||
562 | kfree(host); | 619 | kfree(host); |
563 | 620 | ||
564 | return 0; | 621 | return 0; |
565 | } | 622 | } |
566 | 623 | ||
567 | static struct platform_driver at91_nand_driver = { | 624 | static struct platform_driver atmel_nand_driver = { |
568 | .probe = at91_nand_probe, | 625 | .remove = __exit_p(atmel_nand_remove), |
569 | .remove = at91_nand_remove, | ||
570 | .driver = { | 626 | .driver = { |
571 | .name = "at91_nand", | 627 | .name = "atmel_nand", |
572 | .owner = THIS_MODULE, | 628 | .owner = THIS_MODULE, |
573 | }, | 629 | }, |
574 | }; | 630 | }; |
575 | 631 | ||
576 | static int __init at91_nand_init(void) | 632 | static int __init atmel_nand_init(void) |
577 | { | 633 | { |
578 | return platform_driver_register(&at91_nand_driver); | 634 | return platform_driver_probe(&atmel_nand_driver, atmel_nand_probe); |
579 | } | 635 | } |
580 | 636 | ||
581 | 637 | ||
582 | static void __exit at91_nand_exit(void) | 638 | static void __exit atmel_nand_exit(void) |
583 | { | 639 | { |
584 | platform_driver_unregister(&at91_nand_driver); | 640 | platform_driver_unregister(&atmel_nand_driver); |
585 | } | 641 | } |
586 | 642 | ||
587 | 643 | ||
588 | module_init(at91_nand_init); | 644 | module_init(atmel_nand_init); |
589 | module_exit(at91_nand_exit); | 645 | module_exit(atmel_nand_exit); |
590 | 646 | ||
591 | MODULE_LICENSE("GPL"); | 647 | MODULE_LICENSE("GPL"); |
592 | MODULE_AUTHOR("Rick Bronson"); | 648 | MODULE_AUTHOR("Rick Bronson"); |
593 | MODULE_DESCRIPTION("NAND/SmartMedia driver for AT91RM9200 / AT91SAM9"); | 649 | MODULE_DESCRIPTION("NAND/SmartMedia driver for AT91 / AVR32"); |
594 | MODULE_ALIAS("platform:at91_nand"); | 650 | MODULE_ALIAS("platform:atmel_nand"); |
diff --git a/drivers/mtd/nand/atmel_nand_ecc.h b/drivers/mtd/nand/atmel_nand_ecc.h new file mode 100644 index 000000000000..1ee7f993db1c --- /dev/null +++ b/drivers/mtd/nand/atmel_nand_ecc.h | |||
@@ -0,0 +1,36 @@ | |||
1 | /* | ||
2 | * Error Corrected Code Controller (ECC) - System peripherals regsters. | ||
3 | * Based on AT91SAM9260 datasheet revision B. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License as published by the | ||
7 | * Free Software Foundation; either version 2 of the License, or (at your | ||
8 | * option) any later version. | ||
9 | */ | ||
10 | |||
11 | #ifndef ATMEL_NAND_ECC_H | ||
12 | #define ATMEL_NAND_ECC_H | ||
13 | |||
14 | #define ATMEL_ECC_CR 0x00 /* Control register */ | ||
15 | #define ATMEL_ECC_RST (1 << 0) /* Reset parity */ | ||
16 | |||
17 | #define ATMEL_ECC_MR 0x04 /* Mode register */ | ||
18 | #define ATMEL_ECC_PAGESIZE (3 << 0) /* Page Size */ | ||
19 | #define ATMEL_ECC_PAGESIZE_528 (0) | ||
20 | #define ATMEL_ECC_PAGESIZE_1056 (1) | ||
21 | #define ATMEL_ECC_PAGESIZE_2112 (2) | ||
22 | #define ATMEL_ECC_PAGESIZE_4224 (3) | ||
23 | |||
24 | #define ATMEL_ECC_SR 0x08 /* Status register */ | ||
25 | #define ATMEL_ECC_RECERR (1 << 0) /* Recoverable Error */ | ||
26 | #define ATMEL_ECC_ECCERR (1 << 1) /* ECC Single Bit Error */ | ||
27 | #define ATMEL_ECC_MULERR (1 << 2) /* Multiple Errors */ | ||
28 | |||
29 | #define ATMEL_ECC_PR 0x0c /* Parity register */ | ||
30 | #define ATMEL_ECC_BITADDR (0xf << 0) /* Bit Error Address */ | ||
31 | #define ATMEL_ECC_WORDADDR (0xfff << 4) /* Word Error Address */ | ||
32 | |||
33 | #define ATMEL_ECC_NPR 0x10 /* NParity register */ | ||
34 | #define ATMEL_ECC_NPARITY (0xffff << 0) /* NParity */ | ||
35 | |||
36 | #endif | ||
diff --git a/drivers/mtd/nand/au1550nd.c b/drivers/mtd/nand/au1550nd.c index 09e421a96893..761946ea45b1 100644 --- a/drivers/mtd/nand/au1550nd.c +++ b/drivers/mtd/nand/au1550nd.c | |||
@@ -3,8 +3,6 @@ | |||
3 | * | 3 | * |
4 | * Copyright (C) 2004 Embedded Edge, LLC | 4 | * Copyright (C) 2004 Embedded Edge, LLC |
5 | * | 5 | * |
6 | * $Id: au1550nd.c,v 1.13 2005/11/07 11:14:30 gleixner Exp $ | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
9 | * it under the terms of the GNU General Public License version 2 as | 7 | * it under the terms of the GNU General Public License version 2 as |
10 | * published by the Free Software Foundation. | 8 | * published by the Free Software Foundation. |
@@ -604,8 +602,6 @@ module_init(au1xxx_nand_init); | |||
604 | */ | 602 | */ |
605 | static void __exit au1550_cleanup(void) | 603 | static void __exit au1550_cleanup(void) |
606 | { | 604 | { |
607 | struct nand_chip *this = (struct nand_chip *)&au1550_mtd[1]; | ||
608 | |||
609 | /* Release resources, unregister device */ | 605 | /* Release resources, unregister device */ |
610 | nand_release(au1550_mtd); | 606 | nand_release(au1550_mtd); |
611 | 607 | ||
diff --git a/drivers/mtd/nand/autcpu12.c b/drivers/mtd/nand/autcpu12.c index dd38011ee0b7..553dd7e9b41c 100644 --- a/drivers/mtd/nand/autcpu12.c +++ b/drivers/mtd/nand/autcpu12.c | |||
@@ -6,8 +6,6 @@ | |||
6 | * Derived from drivers/mtd/spia.c | 6 | * Derived from drivers/mtd/spia.c |
7 | * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) | 7 | * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) |
8 | * | 8 | * |
9 | * $Id: autcpu12.c,v 1.23 2005/11/07 11:14:30 gleixner Exp $ | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | 9 | * This program is free software; you can redistribute it and/or modify |
12 | * it under the terms of the GNU General Public License version 2 as | 10 | * it under the terms of the GNU General Public License version 2 as |
13 | * published by the Free Software Foundation. | 11 | * published by the Free Software Foundation. |
diff --git a/drivers/mtd/nand/cafe_nand.c b/drivers/mtd/nand/cafe_nand.c index da6ceaa80ba1..95345d051579 100644 --- a/drivers/mtd/nand/cafe_nand.c +++ b/drivers/mtd/nand/cafe_nand.c | |||
@@ -626,10 +626,12 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev, | |||
626 | { | 626 | { |
627 | struct mtd_info *mtd; | 627 | struct mtd_info *mtd; |
628 | struct cafe_priv *cafe; | 628 | struct cafe_priv *cafe; |
629 | struct mtd_partition *parts; | ||
630 | uint32_t ctrl; | 629 | uint32_t ctrl; |
631 | int nr_parts; | ||
632 | int err = 0; | 630 | int err = 0; |
631 | #ifdef CONFIG_MTD_PARTITIONS | ||
632 | struct mtd_partition *parts; | ||
633 | int nr_parts; | ||
634 | #endif | ||
633 | 635 | ||
634 | /* Very old versions shared the same PCI ident for all three | 636 | /* Very old versions shared the same PCI ident for all three |
635 | functions on the chip. Verify the class too... */ | 637 | functions on the chip. Verify the class too... */ |
diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c index 0e72153b3297..765d4f0f7c86 100644 --- a/drivers/mtd/nand/diskonchip.c +++ b/drivers/mtd/nand/diskonchip.c | |||
@@ -15,8 +15,6 @@ | |||
15 | * converted to the generic Reed-Solomon library by Thomas Gleixner <tglx@linutronix.de> | 15 | * converted to the generic Reed-Solomon library by Thomas Gleixner <tglx@linutronix.de> |
16 | * | 16 | * |
17 | * Interface to generic NAND code for M-Systems DiskOnChip devices | 17 | * Interface to generic NAND code for M-Systems DiskOnChip devices |
18 | * | ||
19 | * $Id: diskonchip.c,v 1.55 2005/11/07 11:14:30 gleixner Exp $ | ||
20 | */ | 18 | */ |
21 | 19 | ||
22 | #include <linux/kernel.h> | 20 | #include <linux/kernel.h> |
@@ -54,8 +52,6 @@ static unsigned long __initdata doc_locations[] = { | |||
54 | 0xe0000, 0xe2000, 0xe4000, 0xe6000, | 52 | 0xe0000, 0xe2000, 0xe4000, 0xe6000, |
55 | 0xe8000, 0xea000, 0xec000, 0xee000, | 53 | 0xe8000, 0xea000, 0xec000, 0xee000, |
56 | #endif /* CONFIG_MTD_DOCPROBE_HIGH */ | 54 | #endif /* CONFIG_MTD_DOCPROBE_HIGH */ |
57 | #elif defined(__PPC__) | ||
58 | 0xe4000000, | ||
59 | #else | 55 | #else |
60 | #warning Unknown architecture for DiskOnChip. No default probe locations defined | 56 | #warning Unknown architecture for DiskOnChip. No default probe locations defined |
61 | #endif | 57 | #endif |
diff --git a/drivers/mtd/nand/edb7312.c b/drivers/mtd/nand/edb7312.c index ba67bbec20d3..387e4352903e 100644 --- a/drivers/mtd/nand/edb7312.c +++ b/drivers/mtd/nand/edb7312.c | |||
@@ -6,8 +6,6 @@ | |||
6 | * Derived from drivers/mtd/nand/autcpu12.c | 6 | * Derived from drivers/mtd/nand/autcpu12.c |
7 | * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de) | 7 | * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de) |
8 | * | 8 | * |
9 | * $Id: edb7312.c,v 1.12 2005/11/07 11:14:30 gleixner Exp $ | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | 9 | * This program is free software; you can redistribute it and/or modify |
12 | * it under the terms of the GNU General Public License version 2 as | 10 | * it under the terms of the GNU General Public License version 2 as |
13 | * published by the Free Software Foundation. | 11 | * published by the Free Software Foundation. |
diff --git a/drivers/mtd/nand/excite_nandflash.c b/drivers/mtd/nand/excite_nandflash.c index bed87290decc..ced14b5294d5 100644 --- a/drivers/mtd/nand/excite_nandflash.c +++ b/drivers/mtd/nand/excite_nandflash.c | |||
@@ -209,7 +209,7 @@ static int __init excite_nand_probe(struct device *dev) | |||
209 | if (likely(!scan_res)) { | 209 | if (likely(!scan_res)) { |
210 | DEBUG(MTD_DEBUG_LEVEL2, "%s: register partitions\n", module_id); | 210 | DEBUG(MTD_DEBUG_LEVEL2, "%s: register partitions\n", module_id); |
211 | add_mtd_partitions(&drvdata->board_mtd, partition_info, | 211 | add_mtd_partitions(&drvdata->board_mtd, partition_info, |
212 | sizeof partition_info / sizeof partition_info[0]); | 212 | ARRAY_SIZE(partition_info)); |
213 | } else { | 213 | } else { |
214 | iounmap(drvdata->regs); | 214 | iounmap(drvdata->regs); |
215 | kfree(drvdata); | 215 | kfree(drvdata); |
diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c index 4b69aacdf5ca..9dff51351f4f 100644 --- a/drivers/mtd/nand/fsl_elbc_nand.c +++ b/drivers/mtd/nand/fsl_elbc_nand.c | |||
@@ -89,7 +89,6 @@ static struct nand_ecclayout fsl_elbc_oob_sp_eccm0 = { | |||
89 | .eccbytes = 3, | 89 | .eccbytes = 3, |
90 | .eccpos = {6, 7, 8}, | 90 | .eccpos = {6, 7, 8}, |
91 | .oobfree = { {0, 5}, {9, 7} }, | 91 | .oobfree = { {0, 5}, {9, 7} }, |
92 | .oobavail = 12, | ||
93 | }; | 92 | }; |
94 | 93 | ||
95 | /* Small Page FLASH with FMR[ECCM] = 1 */ | 94 | /* Small Page FLASH with FMR[ECCM] = 1 */ |
@@ -97,7 +96,6 @@ static struct nand_ecclayout fsl_elbc_oob_sp_eccm1 = { | |||
97 | .eccbytes = 3, | 96 | .eccbytes = 3, |
98 | .eccpos = {8, 9, 10}, | 97 | .eccpos = {8, 9, 10}, |
99 | .oobfree = { {0, 5}, {6, 2}, {11, 5} }, | 98 | .oobfree = { {0, 5}, {6, 2}, {11, 5} }, |
100 | .oobavail = 12, | ||
101 | }; | 99 | }; |
102 | 100 | ||
103 | /* Large Page FLASH with FMR[ECCM] = 0 */ | 101 | /* Large Page FLASH with FMR[ECCM] = 0 */ |
@@ -105,7 +103,6 @@ static struct nand_ecclayout fsl_elbc_oob_lp_eccm0 = { | |||
105 | .eccbytes = 12, | 103 | .eccbytes = 12, |
106 | .eccpos = {6, 7, 8, 22, 23, 24, 38, 39, 40, 54, 55, 56}, | 104 | .eccpos = {6, 7, 8, 22, 23, 24, 38, 39, 40, 54, 55, 56}, |
107 | .oobfree = { {1, 5}, {9, 13}, {25, 13}, {41, 13}, {57, 7} }, | 105 | .oobfree = { {1, 5}, {9, 13}, {25, 13}, {41, 13}, {57, 7} }, |
108 | .oobavail = 48, | ||
109 | }; | 106 | }; |
110 | 107 | ||
111 | /* Large Page FLASH with FMR[ECCM] = 1 */ | 108 | /* Large Page FLASH with FMR[ECCM] = 1 */ |
@@ -113,7 +110,48 @@ static struct nand_ecclayout fsl_elbc_oob_lp_eccm1 = { | |||
113 | .eccbytes = 12, | 110 | .eccbytes = 12, |
114 | .eccpos = {8, 9, 10, 24, 25, 26, 40, 41, 42, 56, 57, 58}, | 111 | .eccpos = {8, 9, 10, 24, 25, 26, 40, 41, 42, 56, 57, 58}, |
115 | .oobfree = { {1, 7}, {11, 13}, {27, 13}, {43, 13}, {59, 5} }, | 112 | .oobfree = { {1, 7}, {11, 13}, {27, 13}, {43, 13}, {59, 5} }, |
116 | .oobavail = 48, | 113 | }; |
114 | |||
115 | /* | ||
116 | * fsl_elbc_oob_lp_eccm* specify that LP NAND's OOB free area starts at offset | ||
117 | * 1, so we have to adjust bad block pattern. This pattern should be used for | ||
118 | * x8 chips only. So far hardware does not support x16 chips anyway. | ||
119 | */ | ||
120 | static u8 scan_ff_pattern[] = { 0xff, }; | ||
121 | |||
122 | static struct nand_bbt_descr largepage_memorybased = { | ||
123 | .options = 0, | ||
124 | .offs = 0, | ||
125 | .len = 1, | ||
126 | .pattern = scan_ff_pattern, | ||
127 | }; | ||
128 | |||
129 | /* | ||
130 | * ELBC may use HW ECC, so that OOB offsets, that NAND core uses for bbt, | ||
131 | * interfere with ECC positions, that's why we implement our own descriptors. | ||
132 | * OOB {11, 5}, works for both SP and LP chips, with ECCM = 1 and ECCM = 0. | ||
133 | */ | ||
134 | static u8 bbt_pattern[] = {'B', 'b', 't', '0' }; | ||
135 | static u8 mirror_pattern[] = {'1', 't', 'b', 'B' }; | ||
136 | |||
137 | static struct nand_bbt_descr bbt_main_descr = { | ||
138 | .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | | ||
139 | NAND_BBT_2BIT | NAND_BBT_VERSION, | ||
140 | .offs = 11, | ||
141 | .len = 4, | ||
142 | .veroffs = 15, | ||
143 | .maxblocks = 4, | ||
144 | .pattern = bbt_pattern, | ||
145 | }; | ||
146 | |||
147 | static struct nand_bbt_descr bbt_mirror_descr = { | ||
148 | .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | | ||
149 | NAND_BBT_2BIT | NAND_BBT_VERSION, | ||
150 | .offs = 11, | ||
151 | .len = 4, | ||
152 | .veroffs = 15, | ||
153 | .maxblocks = 4, | ||
154 | .pattern = mirror_pattern, | ||
117 | }; | 155 | }; |
118 | 156 | ||
119 | /*=================================*/ | 157 | /*=================================*/ |
@@ -687,8 +725,7 @@ static int fsl_elbc_chip_init_tail(struct mtd_info *mtd) | |||
687 | chip->ecc.layout = (priv->fmr & FMR_ECCM) ? | 725 | chip->ecc.layout = (priv->fmr & FMR_ECCM) ? |
688 | &fsl_elbc_oob_lp_eccm1 : | 726 | &fsl_elbc_oob_lp_eccm1 : |
689 | &fsl_elbc_oob_lp_eccm0; | 727 | &fsl_elbc_oob_lp_eccm0; |
690 | mtd->ecclayout = chip->ecc.layout; | 728 | chip->badblock_pattern = &largepage_memorybased; |
691 | mtd->oobavail = chip->ecc.layout->oobavail; | ||
692 | } | 729 | } |
693 | } else { | 730 | } else { |
694 | dev_err(ctrl->dev, | 731 | dev_err(ctrl->dev, |
@@ -752,8 +789,12 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv) | |||
752 | chip->cmdfunc = fsl_elbc_cmdfunc; | 789 | chip->cmdfunc = fsl_elbc_cmdfunc; |
753 | chip->waitfunc = fsl_elbc_wait; | 790 | chip->waitfunc = fsl_elbc_wait; |
754 | 791 | ||
792 | chip->bbt_td = &bbt_main_descr; | ||
793 | chip->bbt_md = &bbt_mirror_descr; | ||
794 | |||
755 | /* set up nand options */ | 795 | /* set up nand options */ |
756 | chip->options = NAND_NO_READRDY | NAND_NO_AUTOINCR; | 796 | chip->options = NAND_NO_READRDY | NAND_NO_AUTOINCR | |
797 | NAND_USE_FLASH_BBT; | ||
757 | 798 | ||
758 | chip->controller = &ctrl->controller; | 799 | chip->controller = &ctrl->controller; |
759 | chip->priv = priv; | 800 | chip->priv = priv; |
@@ -795,8 +836,8 @@ static int fsl_elbc_chip_remove(struct fsl_elbc_mtd *priv) | |||
795 | return 0; | 836 | return 0; |
796 | } | 837 | } |
797 | 838 | ||
798 | static int fsl_elbc_chip_probe(struct fsl_elbc_ctrl *ctrl, | 839 | static int __devinit fsl_elbc_chip_probe(struct fsl_elbc_ctrl *ctrl, |
799 | struct device_node *node) | 840 | struct device_node *node) |
800 | { | 841 | { |
801 | struct fsl_lbc_regs __iomem *lbc = ctrl->regs; | 842 | struct fsl_lbc_regs __iomem *lbc = ctrl->regs; |
802 | struct fsl_elbc_mtd *priv; | 843 | struct fsl_elbc_mtd *priv; |
@@ -917,7 +958,7 @@ static int __devinit fsl_elbc_ctrl_init(struct fsl_elbc_ctrl *ctrl) | |||
917 | return 0; | 958 | return 0; |
918 | } | 959 | } |
919 | 960 | ||
920 | static int __devexit fsl_elbc_ctrl_remove(struct of_device *ofdev) | 961 | static int fsl_elbc_ctrl_remove(struct of_device *ofdev) |
921 | { | 962 | { |
922 | struct fsl_elbc_ctrl *ctrl = dev_get_drvdata(&ofdev->dev); | 963 | struct fsl_elbc_ctrl *ctrl = dev_get_drvdata(&ofdev->dev); |
923 | int i; | 964 | int i; |
@@ -1041,7 +1082,7 @@ static struct of_platform_driver fsl_elbc_ctrl_driver = { | |||
1041 | }, | 1082 | }, |
1042 | .match_table = fsl_elbc_match, | 1083 | .match_table = fsl_elbc_match, |
1043 | .probe = fsl_elbc_ctrl_probe, | 1084 | .probe = fsl_elbc_ctrl_probe, |
1044 | .remove = __devexit_p(fsl_elbc_ctrl_remove), | 1085 | .remove = fsl_elbc_ctrl_remove, |
1045 | }; | 1086 | }; |
1046 | 1087 | ||
1047 | static int __init fsl_elbc_init(void) | 1088 | static int __init fsl_elbc_init(void) |
diff --git a/drivers/mtd/nand/h1910.c b/drivers/mtd/nand/h1910.c index 2d585d2d090c..9e59de501c2e 100644 --- a/drivers/mtd/nand/h1910.c +++ b/drivers/mtd/nand/h1910.c | |||
@@ -7,8 +7,6 @@ | |||
7 | * Copyright (C) 2002 Marius Gröger (mag@sysgo.de) | 7 | * Copyright (C) 2002 Marius Gröger (mag@sysgo.de) |
8 | * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de) | 8 | * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de) |
9 | * | 9 | * |
10 | * $Id: h1910.c,v 1.6 2005/11/07 11:14:30 gleixner Exp $ | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
13 | * it under the terms of the GNU General Public License version 2 as | 11 | * it under the terms of the GNU General Public License version 2 as |
14 | * published by the Free Software Foundation. | 12 | * published by the Free Software Foundation. |
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index ba1bdf787323..d1129bae6c27 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c | |||
@@ -798,6 +798,87 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, | |||
798 | } | 798 | } |
799 | 799 | ||
800 | /** | 800 | /** |
801 | * nand_read_subpage - [REPLACABLE] software ecc based sub-page read function | ||
802 | * @mtd: mtd info structure | ||
803 | * @chip: nand chip info structure | ||
804 | * @dataofs offset of requested data within the page | ||
805 | * @readlen data length | ||
806 | * @buf: buffer to store read data | ||
807 | */ | ||
808 | static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi) | ||
809 | { | ||
810 | int start_step, end_step, num_steps; | ||
811 | uint32_t *eccpos = chip->ecc.layout->eccpos; | ||
812 | uint8_t *p; | ||
813 | int data_col_addr, i, gaps = 0; | ||
814 | int datafrag_len, eccfrag_len, aligned_len, aligned_pos; | ||
815 | int busw = (chip->options & NAND_BUSWIDTH_16) ? 2 : 1; | ||
816 | |||
817 | /* Column address wihin the page aligned to ECC size (256bytes). */ | ||
818 | start_step = data_offs / chip->ecc.size; | ||
819 | end_step = (data_offs + readlen - 1) / chip->ecc.size; | ||
820 | num_steps = end_step - start_step + 1; | ||
821 | |||
822 | /* Data size aligned to ECC ecc.size*/ | ||
823 | datafrag_len = num_steps * chip->ecc.size; | ||
824 | eccfrag_len = num_steps * chip->ecc.bytes; | ||
825 | |||
826 | data_col_addr = start_step * chip->ecc.size; | ||
827 | /* If we read not a page aligned data */ | ||
828 | if (data_col_addr != 0) | ||
829 | chip->cmdfunc(mtd, NAND_CMD_RNDOUT, data_col_addr, -1); | ||
830 | |||
831 | p = bufpoi + data_col_addr; | ||
832 | chip->read_buf(mtd, p, datafrag_len); | ||
833 | |||
834 | /* Calculate ECC */ | ||
835 | for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size) | ||
836 | chip->ecc.calculate(mtd, p, &chip->buffers->ecccalc[i]); | ||
837 | |||
838 | /* The performance is faster if to position offsets | ||
839 | according to ecc.pos. Let make sure here that | ||
840 | there are no gaps in ecc positions */ | ||
841 | for (i = 0; i < eccfrag_len - 1; i++) { | ||
842 | if (eccpos[i + start_step * chip->ecc.bytes] + 1 != | ||
843 | eccpos[i + start_step * chip->ecc.bytes + 1]) { | ||
844 | gaps = 1; | ||
845 | break; | ||
846 | } | ||
847 | } | ||
848 | if (gaps) { | ||
849 | chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize, -1); | ||
850 | chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); | ||
851 | } else { | ||
852 | /* send the command to read the particular ecc bytes */ | ||
853 | /* take care about buswidth alignment in read_buf */ | ||
854 | aligned_pos = eccpos[start_step * chip->ecc.bytes] & ~(busw - 1); | ||
855 | aligned_len = eccfrag_len; | ||
856 | if (eccpos[start_step * chip->ecc.bytes] & (busw - 1)) | ||
857 | aligned_len++; | ||
858 | if (eccpos[(start_step + num_steps) * chip->ecc.bytes] & (busw - 1)) | ||
859 | aligned_len++; | ||
860 | |||
861 | chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize + aligned_pos, -1); | ||
862 | chip->read_buf(mtd, &chip->oob_poi[aligned_pos], aligned_len); | ||
863 | } | ||
864 | |||
865 | for (i = 0; i < eccfrag_len; i++) | ||
866 | chip->buffers->ecccode[i] = chip->oob_poi[eccpos[i + start_step * chip->ecc.bytes]]; | ||
867 | |||
868 | p = bufpoi + data_col_addr; | ||
869 | for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size) { | ||
870 | int stat; | ||
871 | |||
872 | stat = chip->ecc.correct(mtd, p, &chip->buffers->ecccode[i], &chip->buffers->ecccalc[i]); | ||
873 | if (stat == -1) | ||
874 | mtd->ecc_stats.failed++; | ||
875 | else | ||
876 | mtd->ecc_stats.corrected += stat; | ||
877 | } | ||
878 | return 0; | ||
879 | } | ||
880 | |||
881 | /** | ||
801 | * nand_read_page_hwecc - [REPLACABLE] hardware ecc based page read function | 882 | * nand_read_page_hwecc - [REPLACABLE] hardware ecc based page read function |
802 | * @mtd: mtd info structure | 883 | * @mtd: mtd info structure |
803 | * @chip: nand chip info structure | 884 | * @chip: nand chip info structure |
@@ -994,6 +1075,8 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, | |||
994 | /* Now read the page into the buffer */ | 1075 | /* Now read the page into the buffer */ |
995 | if (unlikely(ops->mode == MTD_OOB_RAW)) | 1076 | if (unlikely(ops->mode == MTD_OOB_RAW)) |
996 | ret = chip->ecc.read_page_raw(mtd, chip, bufpoi); | 1077 | ret = chip->ecc.read_page_raw(mtd, chip, bufpoi); |
1078 | else if (!aligned && NAND_SUBPAGE_READ(chip) && !oob) | ||
1079 | ret = chip->ecc.read_subpage(mtd, chip, col, bytes, bufpoi); | ||
997 | else | 1080 | else |
998 | ret = chip->ecc.read_page(mtd, chip, bufpoi); | 1081 | ret = chip->ecc.read_page(mtd, chip, bufpoi); |
999 | if (ret < 0) | 1082 | if (ret < 0) |
@@ -1001,7 +1084,8 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, | |||
1001 | 1084 | ||
1002 | /* Transfer not aligned data */ | 1085 | /* Transfer not aligned data */ |
1003 | if (!aligned) { | 1086 | if (!aligned) { |
1004 | chip->pagebuf = realpage; | 1087 | if (!NAND_SUBPAGE_READ(chip) && !oob) |
1088 | chip->pagebuf = realpage; | ||
1005 | memcpy(buf, chip->buffers->databuf + col, bytes); | 1089 | memcpy(buf, chip->buffers->databuf + col, bytes); |
1006 | } | 1090 | } |
1007 | 1091 | ||
@@ -2521,6 +2605,7 @@ int nand_scan_tail(struct mtd_info *mtd) | |||
2521 | chip->ecc.calculate = nand_calculate_ecc; | 2605 | chip->ecc.calculate = nand_calculate_ecc; |
2522 | chip->ecc.correct = nand_correct_data; | 2606 | chip->ecc.correct = nand_correct_data; |
2523 | chip->ecc.read_page = nand_read_page_swecc; | 2607 | chip->ecc.read_page = nand_read_page_swecc; |
2608 | chip->ecc.read_subpage = nand_read_subpage; | ||
2524 | chip->ecc.write_page = nand_write_page_swecc; | 2609 | chip->ecc.write_page = nand_write_page_swecc; |
2525 | chip->ecc.read_oob = nand_read_oob_std; | 2610 | chip->ecc.read_oob = nand_read_oob_std; |
2526 | chip->ecc.write_oob = nand_write_oob_std; | 2611 | chip->ecc.write_oob = nand_write_oob_std; |
diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index 5e121ceaa598..0b1c48595f12 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c | |||
@@ -6,8 +6,6 @@ | |||
6 | * | 6 | * |
7 | * Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de) | 7 | * Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de) |
8 | * | 8 | * |
9 | * $Id: nand_bbt.c,v 1.36 2005/11/07 11:14:30 gleixner Exp $ | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | 9 | * This program is free software; you can redistribute it and/or modify |
12 | * it under the terms of the GNU General Public License version 2 as | 10 | * it under the terms of the GNU General Public License version 2 as |
13 | * published by the Free Software Foundation. | 11 | * published by the Free Software Foundation. |
diff --git a/drivers/mtd/nand/nand_ecc.c b/drivers/mtd/nand/nand_ecc.c index 9003a135e050..918a806a8471 100644 --- a/drivers/mtd/nand/nand_ecc.c +++ b/drivers/mtd/nand/nand_ecc.c | |||
@@ -9,8 +9,6 @@ | |||
9 | * | 9 | * |
10 | * Copyright (C) 2006 Thomas Gleixner <tglx@linutronix.de> | 10 | * Copyright (C) 2006 Thomas Gleixner <tglx@linutronix.de> |
11 | * | 11 | * |
12 | * $Id: nand_ecc.c,v 1.15 2005/11/07 11:14:30 gleixner Exp $ | ||
13 | * | ||
14 | * This file is free software; you can redistribute it and/or modify it | 12 | * This file is free software; you can redistribute it and/or modify it |
15 | * under the terms of the GNU General Public License as published by the | 13 | * under the terms of the GNU General Public License as published by the |
16 | * Free Software Foundation; either version 2 or (at your option) any | 14 | * Free Software Foundation; either version 2 or (at your option) any |
diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c index a3e3ab0185d5..69ee2c90eb0b 100644 --- a/drivers/mtd/nand/nand_ids.c +++ b/drivers/mtd/nand/nand_ids.c | |||
@@ -3,8 +3,6 @@ | |||
3 | * | 3 | * |
4 | * Copyright (C) 2002 Thomas Gleixner (tglx@linutronix.de) | 4 | * Copyright (C) 2002 Thomas Gleixner (tglx@linutronix.de) |
5 | * | 5 | * |
6 | * $Id: nand_ids.c,v 1.16 2005/11/07 11:14:31 gleixner Exp $ | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
9 | * it under the terms of the GNU General Public License version 2 as | 7 | * it under the terms of the GNU General Public License version 2 as |
10 | * published by the Free Software Foundation. | 8 | * published by the Free Software Foundation. |
diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index bb885d1fcab5..ecd70e2504f6 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c | |||
@@ -21,8 +21,6 @@ | |||
21 | * You should have received a copy of the GNU General Public License | 21 | * You should have received a copy of the GNU General Public License |
22 | * along with this program; if not, write to the Free Software | 22 | * along with this program; if not, write to the Free Software |
23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA | 23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA |
24 | * | ||
25 | * $Id: nandsim.c,v 1.8 2005/03/19 15:33:56 dedekind Exp $ | ||
26 | */ | 24 | */ |
27 | 25 | ||
28 | #include <linux/init.h> | 26 | #include <linux/init.h> |
@@ -39,6 +37,7 @@ | |||
39 | #include <linux/delay.h> | 37 | #include <linux/delay.h> |
40 | #include <linux/list.h> | 38 | #include <linux/list.h> |
41 | #include <linux/random.h> | 39 | #include <linux/random.h> |
40 | #include <asm/div64.h> | ||
42 | 41 | ||
43 | /* Default simulator parameters values */ | 42 | /* Default simulator parameters values */ |
44 | #if !defined(CONFIG_NANDSIM_FIRST_ID_BYTE) || \ | 43 | #if !defined(CONFIG_NANDSIM_FIRST_ID_BYTE) || \ |
@@ -298,11 +297,11 @@ struct nandsim { | |||
298 | 297 | ||
299 | /* NAND flash "geometry" */ | 298 | /* NAND flash "geometry" */ |
300 | struct nandsin_geometry { | 299 | struct nandsin_geometry { |
301 | uint32_t totsz; /* total flash size, bytes */ | 300 | uint64_t totsz; /* total flash size, bytes */ |
302 | uint32_t secsz; /* flash sector (erase block) size, bytes */ | 301 | uint32_t secsz; /* flash sector (erase block) size, bytes */ |
303 | uint pgsz; /* NAND flash page size, bytes */ | 302 | uint pgsz; /* NAND flash page size, bytes */ |
304 | uint oobsz; /* page OOB area size, bytes */ | 303 | uint oobsz; /* page OOB area size, bytes */ |
305 | uint32_t totszoob; /* total flash size including OOB, bytes */ | 304 | uint64_t totszoob; /* total flash size including OOB, bytes */ |
306 | uint pgszoob; /* page size including OOB , bytes*/ | 305 | uint pgszoob; /* page size including OOB , bytes*/ |
307 | uint secszoob; /* sector size including OOB, bytes */ | 306 | uint secszoob; /* sector size including OOB, bytes */ |
308 | uint pgnum; /* total number of pages */ | 307 | uint pgnum; /* total number of pages */ |
@@ -459,6 +458,12 @@ static char *get_partition_name(int i) | |||
459 | return kstrdup(buf, GFP_KERNEL); | 458 | return kstrdup(buf, GFP_KERNEL); |
460 | } | 459 | } |
461 | 460 | ||
461 | static u_int64_t divide(u_int64_t n, u_int32_t d) | ||
462 | { | ||
463 | do_div(n, d); | ||
464 | return n; | ||
465 | } | ||
466 | |||
462 | /* | 467 | /* |
463 | * Initialize the nandsim structure. | 468 | * Initialize the nandsim structure. |
464 | * | 469 | * |
@@ -469,8 +474,8 @@ static int init_nandsim(struct mtd_info *mtd) | |||
469 | struct nand_chip *chip = (struct nand_chip *)mtd->priv; | 474 | struct nand_chip *chip = (struct nand_chip *)mtd->priv; |
470 | struct nandsim *ns = (struct nandsim *)(chip->priv); | 475 | struct nandsim *ns = (struct nandsim *)(chip->priv); |
471 | int i, ret = 0; | 476 | int i, ret = 0; |
472 | u_int32_t remains; | 477 | u_int64_t remains; |
473 | u_int32_t next_offset; | 478 | u_int64_t next_offset; |
474 | 479 | ||
475 | if (NS_IS_INITIALIZED(ns)) { | 480 | if (NS_IS_INITIALIZED(ns)) { |
476 | NS_ERR("init_nandsim: nandsim is already initialized\n"); | 481 | NS_ERR("init_nandsim: nandsim is already initialized\n"); |
@@ -487,8 +492,8 @@ static int init_nandsim(struct mtd_info *mtd) | |||
487 | ns->geom.oobsz = mtd->oobsize; | 492 | ns->geom.oobsz = mtd->oobsize; |
488 | ns->geom.secsz = mtd->erasesize; | 493 | ns->geom.secsz = mtd->erasesize; |
489 | ns->geom.pgszoob = ns->geom.pgsz + ns->geom.oobsz; | 494 | ns->geom.pgszoob = ns->geom.pgsz + ns->geom.oobsz; |
490 | ns->geom.pgnum = ns->geom.totsz / ns->geom.pgsz; | 495 | ns->geom.pgnum = divide(ns->geom.totsz, ns->geom.pgsz); |
491 | ns->geom.totszoob = ns->geom.totsz + ns->geom.pgnum * ns->geom.oobsz; | 496 | ns->geom.totszoob = ns->geom.totsz + (uint64_t)ns->geom.pgnum * ns->geom.oobsz; |
492 | ns->geom.secshift = ffs(ns->geom.secsz) - 1; | 497 | ns->geom.secshift = ffs(ns->geom.secsz) - 1; |
493 | ns->geom.pgshift = chip->page_shift; | 498 | ns->geom.pgshift = chip->page_shift; |
494 | ns->geom.oobshift = ffs(ns->geom.oobsz) - 1; | 499 | ns->geom.oobshift = ffs(ns->geom.oobsz) - 1; |
@@ -511,7 +516,7 @@ static int init_nandsim(struct mtd_info *mtd) | |||
511 | } | 516 | } |
512 | 517 | ||
513 | if (ns->options & OPT_SMALLPAGE) { | 518 | if (ns->options & OPT_SMALLPAGE) { |
514 | if (ns->geom.totsz < (32 << 20)) { | 519 | if (ns->geom.totsz <= (32 << 20)) { |
515 | ns->geom.pgaddrbytes = 3; | 520 | ns->geom.pgaddrbytes = 3; |
516 | ns->geom.secaddrbytes = 2; | 521 | ns->geom.secaddrbytes = 2; |
517 | } else { | 522 | } else { |
@@ -537,15 +542,16 @@ static int init_nandsim(struct mtd_info *mtd) | |||
537 | remains = ns->geom.totsz; | 542 | remains = ns->geom.totsz; |
538 | next_offset = 0; | 543 | next_offset = 0; |
539 | for (i = 0; i < parts_num; ++i) { | 544 | for (i = 0; i < parts_num; ++i) { |
540 | unsigned long part = parts[i]; | 545 | u_int64_t part_sz = (u_int64_t)parts[i] * ns->geom.secsz; |
541 | if (!part || part > remains / ns->geom.secsz) { | 546 | |
547 | if (!part_sz || part_sz > remains) { | ||
542 | NS_ERR("bad partition size.\n"); | 548 | NS_ERR("bad partition size.\n"); |
543 | ret = -EINVAL; | 549 | ret = -EINVAL; |
544 | goto error; | 550 | goto error; |
545 | } | 551 | } |
546 | ns->partitions[i].name = get_partition_name(i); | 552 | ns->partitions[i].name = get_partition_name(i); |
547 | ns->partitions[i].offset = next_offset; | 553 | ns->partitions[i].offset = next_offset; |
548 | ns->partitions[i].size = part * ns->geom.secsz; | 554 | ns->partitions[i].size = part_sz; |
549 | next_offset += ns->partitions[i].size; | 555 | next_offset += ns->partitions[i].size; |
550 | remains -= ns->partitions[i].size; | 556 | remains -= ns->partitions[i].size; |
551 | } | 557 | } |
@@ -573,7 +579,7 @@ static int init_nandsim(struct mtd_info *mtd) | |||
573 | if (ns->busw == 16) | 579 | if (ns->busw == 16) |
574 | NS_WARN("16-bit flashes support wasn't tested\n"); | 580 | NS_WARN("16-bit flashes support wasn't tested\n"); |
575 | 581 | ||
576 | printk("flash size: %u MiB\n", ns->geom.totsz >> 20); | 582 | printk("flash size: %llu MiB\n", ns->geom.totsz >> 20); |
577 | printk("page size: %u bytes\n", ns->geom.pgsz); | 583 | printk("page size: %u bytes\n", ns->geom.pgsz); |
578 | printk("OOB area size: %u bytes\n", ns->geom.oobsz); | 584 | printk("OOB area size: %u bytes\n", ns->geom.oobsz); |
579 | printk("sector size: %u KiB\n", ns->geom.secsz >> 10); | 585 | printk("sector size: %u KiB\n", ns->geom.secsz >> 10); |
@@ -583,7 +589,7 @@ static int init_nandsim(struct mtd_info *mtd) | |||
583 | printk("bits in sector size: %u\n", ns->geom.secshift); | 589 | printk("bits in sector size: %u\n", ns->geom.secshift); |
584 | printk("bits in page size: %u\n", ns->geom.pgshift); | 590 | printk("bits in page size: %u\n", ns->geom.pgshift); |
585 | printk("bits in OOB size: %u\n", ns->geom.oobshift); | 591 | printk("bits in OOB size: %u\n", ns->geom.oobshift); |
586 | printk("flash size with OOB: %u KiB\n", ns->geom.totszoob >> 10); | 592 | printk("flash size with OOB: %llu KiB\n", ns->geom.totszoob >> 10); |
587 | printk("page address bytes: %u\n", ns->geom.pgaddrbytes); | 593 | printk("page address bytes: %u\n", ns->geom.pgaddrbytes); |
588 | printk("sector address bytes: %u\n", ns->geom.secaddrbytes); | 594 | printk("sector address bytes: %u\n", ns->geom.secaddrbytes); |
589 | printk("options: %#x\n", ns->options); | 595 | printk("options: %#x\n", ns->options); |
@@ -825,7 +831,7 @@ static int setup_wear_reporting(struct mtd_info *mtd) | |||
825 | 831 | ||
826 | if (!rptwear) | 832 | if (!rptwear) |
827 | return 0; | 833 | return 0; |
828 | wear_eb_count = mtd->size / mtd->erasesize; | 834 | wear_eb_count = divide(mtd->size, mtd->erasesize); |
829 | mem = wear_eb_count * sizeof(unsigned long); | 835 | mem = wear_eb_count * sizeof(unsigned long); |
830 | if (mem / sizeof(unsigned long) != wear_eb_count) { | 836 | if (mem / sizeof(unsigned long) != wear_eb_count) { |
831 | NS_ERR("Too many erase blocks for wear reporting\n"); | 837 | NS_ERR("Too many erase blocks for wear reporting\n"); |
@@ -2013,7 +2019,7 @@ static int __init ns_init_module(void) | |||
2013 | } | 2019 | } |
2014 | 2020 | ||
2015 | if (overridesize) { | 2021 | if (overridesize) { |
2016 | u_int32_t new_size = nsmtd->erasesize << overridesize; | 2022 | u_int64_t new_size = (u_int64_t)nsmtd->erasesize << overridesize; |
2017 | if (new_size >> overridesize != nsmtd->erasesize) { | 2023 | if (new_size >> overridesize != nsmtd->erasesize) { |
2018 | NS_ERR("overridesize is too big\n"); | 2024 | NS_ERR("overridesize is too big\n"); |
2019 | goto err_exit; | 2025 | goto err_exit; |
@@ -2021,7 +2027,8 @@ static int __init ns_init_module(void) | |||
2021 | /* N.B. This relies on nand_scan not doing anything with the size before we change it */ | 2027 | /* N.B. This relies on nand_scan not doing anything with the size before we change it */ |
2022 | nsmtd->size = new_size; | 2028 | nsmtd->size = new_size; |
2023 | chip->chipsize = new_size; | 2029 | chip->chipsize = new_size; |
2024 | chip->chip_shift = ffs(new_size) - 1; | 2030 | chip->chip_shift = ffs(nsmtd->erasesize) + overridesize - 1; |
2031 | chip->pagemask = (chip->chipsize >> chip->page_shift) - 1; | ||
2025 | } | 2032 | } |
2026 | 2033 | ||
2027 | if ((retval = setup_wear_reporting(nsmtd)) != 0) | 2034 | if ((retval = setup_wear_reporting(nsmtd)) != 0) |
diff --git a/drivers/mtd/nand/ppchameleonevb.c b/drivers/mtd/nand/ppchameleonevb.c index 082073acf20f..cc8658431851 100644 --- a/drivers/mtd/nand/ppchameleonevb.c +++ b/drivers/mtd/nand/ppchameleonevb.c | |||
@@ -6,8 +6,6 @@ | |||
6 | * Derived from drivers/mtd/nand/edb7312.c | 6 | * Derived from drivers/mtd/nand/edb7312.c |
7 | * | 7 | * |
8 | * | 8 | * |
9 | * $Id: ppchameleonevb.c,v 1.7 2005/11/07 11:14:31 gleixner Exp $ | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | 9 | * This program is free software; you can redistribute it and/or modify |
12 | * it under the terms of the GNU General Public License version 2 as | 10 | * it under the terms of the GNU General Public License version 2 as |
13 | * published by the Free Software Foundation. | 11 | * published by the Free Software Foundation. |
diff --git a/drivers/mtd/nand/rtc_from4.c b/drivers/mtd/nand/rtc_from4.c index 26f88215bc47..a033c4cd8e16 100644 --- a/drivers/mtd/nand/rtc_from4.c +++ b/drivers/mtd/nand/rtc_from4.c | |||
@@ -6,8 +6,6 @@ | |||
6 | * Derived from drivers/mtd/nand/spia.c | 6 | * Derived from drivers/mtd/nand/spia.c |
7 | * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) | 7 | * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) |
8 | * | 8 | * |
9 | * $Id: rtc_from4.c,v 1.10 2005/11/07 11:14:31 gleixner Exp $ | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | 9 | * This program is free software; you can redistribute it and/or modify |
12 | * it under the terms of the GNU General Public License version 2 as | 10 | * it under the terms of the GNU General Public License version 2 as |
13 | * published by the Free Software Foundation. | 11 | * published by the Free Software Foundation. |
diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c index b34a460ab679..556139ed1fdf 100644 --- a/drivers/mtd/nand/s3c2410.c +++ b/drivers/mtd/nand/s3c2410.c | |||
@@ -1,26 +1,10 @@ | |||
1 | /* linux/drivers/mtd/nand/s3c2410.c | 1 | /* linux/drivers/mtd/nand/s3c2410.c |
2 | * | 2 | * |
3 | * Copyright (c) 2004,2005 Simtec Electronics | 3 | * Copyright © 2004-2008 Simtec Electronics |
4 | * http://www.simtec.co.uk/products/SWLINUX/ | 4 | * http://armlinux.simtec.co.uk/ |
5 | * Ben Dooks <ben@simtec.co.uk> | 5 | * Ben Dooks <ben@simtec.co.uk> |
6 | * | 6 | * |
7 | * Samsung S3C2410/S3C240 NAND driver | 7 | * Samsung S3C2410/S3C2440/S3C2412 NAND driver |
8 | * | ||
9 | * Changelog: | ||
10 | * 21-Sep-2004 BJD Initial version | ||
11 | * 23-Sep-2004 BJD Multiple device support | ||
12 | * 28-Sep-2004 BJD Fixed ECC placement for Hardware mode | ||
13 | * 12-Oct-2004 BJD Fixed errors in use of platform data | ||
14 | * 18-Feb-2005 BJD Fix sparse errors | ||
15 | * 14-Mar-2005 BJD Applied tglx's code reduction patch | ||
16 | * 02-May-2005 BJD Fixed s3c2440 support | ||
17 | * 02-May-2005 BJD Reduced hwcontrol decode | ||
18 | * 20-Jun-2005 BJD Updated s3c2440 support, fixed timing bug | ||
19 | * 08-Jul-2005 BJD Fix OOPS when no platform data supplied | ||
20 | * 20-Oct-2005 BJD Fix timing calculation bug | ||
21 | * 14-Jan-2006 BJD Allow clock to be stopped when idle | ||
22 | * | ||
23 | * $Id: s3c2410.c,v 1.23 2006/04/01 18:06:29 bjd Exp $ | ||
24 | * | 8 | * |
25 | * This program is free software; you can redistribute it and/or modify | 9 | * This program is free software; you can redistribute it and/or modify |
26 | * it under the terms of the GNU General Public License as published by | 10 | * it under the terms of the GNU General Public License as published by |
@@ -52,6 +36,7 @@ | |||
52 | #include <linux/err.h> | 36 | #include <linux/err.h> |
53 | #include <linux/slab.h> | 37 | #include <linux/slab.h> |
54 | #include <linux/clk.h> | 38 | #include <linux/clk.h> |
39 | #include <linux/cpufreq.h> | ||
55 | 40 | ||
56 | #include <linux/mtd/mtd.h> | 41 | #include <linux/mtd/mtd.h> |
57 | #include <linux/mtd/nand.h> | 42 | #include <linux/mtd/nand.h> |
@@ -120,8 +105,13 @@ struct s3c2410_nand_info { | |||
120 | int sel_bit; | 105 | int sel_bit; |
121 | int mtd_count; | 106 | int mtd_count; |
122 | unsigned long save_sel; | 107 | unsigned long save_sel; |
108 | unsigned long clk_rate; | ||
123 | 109 | ||
124 | enum s3c_cpu_type cpu_type; | 110 | enum s3c_cpu_type cpu_type; |
111 | |||
112 | #ifdef CONFIG_CPU_FREQ | ||
113 | struct notifier_block freq_transition; | ||
114 | #endif | ||
125 | }; | 115 | }; |
126 | 116 | ||
127 | /* conversion functions */ | 117 | /* conversion functions */ |
@@ -179,17 +169,18 @@ static int s3c_nand_calc_rate(int wanted, unsigned long clk, int max) | |||
179 | 169 | ||
180 | /* controller setup */ | 170 | /* controller setup */ |
181 | 171 | ||
182 | static int s3c2410_nand_inithw(struct s3c2410_nand_info *info, | 172 | static int s3c2410_nand_setrate(struct s3c2410_nand_info *info) |
183 | struct platform_device *pdev) | ||
184 | { | 173 | { |
185 | struct s3c2410_platform_nand *plat = to_nand_plat(pdev); | 174 | struct s3c2410_platform_nand *plat = info->platform; |
186 | unsigned long clkrate = clk_get_rate(info->clk); | ||
187 | int tacls_max = (info->cpu_type == TYPE_S3C2412) ? 8 : 4; | 175 | int tacls_max = (info->cpu_type == TYPE_S3C2412) ? 8 : 4; |
188 | int tacls, twrph0, twrph1; | 176 | int tacls, twrph0, twrph1; |
189 | unsigned long cfg = 0; | 177 | unsigned long clkrate = clk_get_rate(info->clk); |
178 | unsigned long set, cfg, mask; | ||
179 | unsigned long flags; | ||
190 | 180 | ||
191 | /* calculate the timing information for the controller */ | 181 | /* calculate the timing information for the controller */ |
192 | 182 | ||
183 | info->clk_rate = clkrate; | ||
193 | clkrate /= 1000; /* turn clock into kHz for ease of use */ | 184 | clkrate /= 1000; /* turn clock into kHz for ease of use */ |
194 | 185 | ||
195 | if (plat != NULL) { | 186 | if (plat != NULL) { |
@@ -211,28 +202,69 @@ static int s3c2410_nand_inithw(struct s3c2410_nand_info *info, | |||
211 | dev_info(info->device, "Tacls=%d, %dns Twrph0=%d %dns, Twrph1=%d %dns\n", | 202 | dev_info(info->device, "Tacls=%d, %dns Twrph0=%d %dns, Twrph1=%d %dns\n", |
212 | tacls, to_ns(tacls, clkrate), twrph0, to_ns(twrph0, clkrate), twrph1, to_ns(twrph1, clkrate)); | 203 | tacls, to_ns(tacls, clkrate), twrph0, to_ns(twrph0, clkrate), twrph1, to_ns(twrph1, clkrate)); |
213 | 204 | ||
205 | switch (info->cpu_type) { | ||
206 | case TYPE_S3C2410: | ||
207 | mask = (S3C2410_NFCONF_TACLS(3) | | ||
208 | S3C2410_NFCONF_TWRPH0(7) | | ||
209 | S3C2410_NFCONF_TWRPH1(7)); | ||
210 | set = S3C2410_NFCONF_EN; | ||
211 | set |= S3C2410_NFCONF_TACLS(tacls - 1); | ||
212 | set |= S3C2410_NFCONF_TWRPH0(twrph0 - 1); | ||
213 | set |= S3C2410_NFCONF_TWRPH1(twrph1 - 1); | ||
214 | break; | ||
215 | |||
216 | case TYPE_S3C2440: | ||
217 | case TYPE_S3C2412: | ||
218 | mask = (S3C2410_NFCONF_TACLS(tacls_max - 1) | | ||
219 | S3C2410_NFCONF_TWRPH0(7) | | ||
220 | S3C2410_NFCONF_TWRPH1(7)); | ||
221 | |||
222 | set = S3C2440_NFCONF_TACLS(tacls - 1); | ||
223 | set |= S3C2440_NFCONF_TWRPH0(twrph0 - 1); | ||
224 | set |= S3C2440_NFCONF_TWRPH1(twrph1 - 1); | ||
225 | break; | ||
226 | |||
227 | default: | ||
228 | /* keep compiler happy */ | ||
229 | mask = 0; | ||
230 | set = 0; | ||
231 | BUG(); | ||
232 | } | ||
233 | |||
234 | dev_dbg(info->device, "NF_CONF is 0x%lx\n", cfg); | ||
235 | |||
236 | local_irq_save(flags); | ||
237 | |||
238 | cfg = readl(info->regs + S3C2410_NFCONF); | ||
239 | cfg &= ~mask; | ||
240 | cfg |= set; | ||
241 | writel(cfg, info->regs + S3C2410_NFCONF); | ||
242 | |||
243 | local_irq_restore(flags); | ||
244 | |||
245 | return 0; | ||
246 | } | ||
247 | |||
248 | static int s3c2410_nand_inithw(struct s3c2410_nand_info *info) | ||
249 | { | ||
250 | int ret; | ||
251 | |||
252 | ret = s3c2410_nand_setrate(info); | ||
253 | if (ret < 0) | ||
254 | return ret; | ||
255 | |||
214 | switch (info->cpu_type) { | 256 | switch (info->cpu_type) { |
215 | case TYPE_S3C2410: | 257 | case TYPE_S3C2410: |
216 | cfg = S3C2410_NFCONF_EN; | 258 | default: |
217 | cfg |= S3C2410_NFCONF_TACLS(tacls - 1); | ||
218 | cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1); | ||
219 | cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1); | ||
220 | break; | 259 | break; |
221 | 260 | ||
222 | case TYPE_S3C2440: | 261 | case TYPE_S3C2440: |
223 | case TYPE_S3C2412: | 262 | case TYPE_S3C2412: |
224 | cfg = S3C2440_NFCONF_TACLS(tacls - 1); | ||
225 | cfg |= S3C2440_NFCONF_TWRPH0(twrph0 - 1); | ||
226 | cfg |= S3C2440_NFCONF_TWRPH1(twrph1 - 1); | ||
227 | |||
228 | /* enable the controller and de-assert nFCE */ | 263 | /* enable the controller and de-assert nFCE */ |
229 | 264 | ||
230 | writel(S3C2440_NFCONT_ENABLE, info->regs + S3C2440_NFCONT); | 265 | writel(S3C2440_NFCONT_ENABLE, info->regs + S3C2440_NFCONT); |
231 | } | 266 | } |
232 | 267 | ||
233 | dev_dbg(info->device, "NF_CONF is 0x%lx\n", cfg); | ||
234 | |||
235 | writel(cfg, info->regs + S3C2410_NFCONF); | ||
236 | return 0; | 268 | return 0; |
237 | } | 269 | } |
238 | 270 | ||
@@ -513,6 +545,52 @@ static void s3c2440_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int | |||
513 | writesl(info->regs + S3C2440_NFDATA, buf, len / 4); | 545 | writesl(info->regs + S3C2440_NFDATA, buf, len / 4); |
514 | } | 546 | } |
515 | 547 | ||
548 | /* cpufreq driver support */ | ||
549 | |||
550 | #ifdef CONFIG_CPU_FREQ | ||
551 | |||
552 | static int s3c2410_nand_cpufreq_transition(struct notifier_block *nb, | ||
553 | unsigned long val, void *data) | ||
554 | { | ||
555 | struct s3c2410_nand_info *info; | ||
556 | unsigned long newclk; | ||
557 | |||
558 | info = container_of(nb, struct s3c2410_nand_info, freq_transition); | ||
559 | newclk = clk_get_rate(info->clk); | ||
560 | |||
561 | if ((val == CPUFREQ_POSTCHANGE && newclk < info->clk_rate) || | ||
562 | (val == CPUFREQ_PRECHANGE && newclk > info->clk_rate)) { | ||
563 | s3c2410_nand_setrate(info); | ||
564 | } | ||
565 | |||
566 | return 0; | ||
567 | } | ||
568 | |||
569 | static inline int s3c2410_nand_cpufreq_register(struct s3c2410_nand_info *info) | ||
570 | { | ||
571 | info->freq_transition.notifier_call = s3c2410_nand_cpufreq_transition; | ||
572 | |||
573 | return cpufreq_register_notifier(&info->freq_transition, | ||
574 | CPUFREQ_TRANSITION_NOTIFIER); | ||
575 | } | ||
576 | |||
577 | static inline void s3c2410_nand_cpufreq_deregister(struct s3c2410_nand_info *info) | ||
578 | { | ||
579 | cpufreq_unregister_notifier(&info->freq_transition, | ||
580 | CPUFREQ_TRANSITION_NOTIFIER); | ||
581 | } | ||
582 | |||
583 | #else | ||
584 | static inline int s3c2410_nand_cpufreq_register(struct s3c2410_nand_info *info) | ||
585 | { | ||
586 | return 0; | ||
587 | } | ||
588 | |||
589 | static inline void s3c2410_nand_cpufreq_deregister(struct s3c2410_nand_info *info) | ||
590 | { | ||
591 | } | ||
592 | #endif | ||
593 | |||
516 | /* device management functions */ | 594 | /* device management functions */ |
517 | 595 | ||
518 | static int s3c2410_nand_remove(struct platform_device *pdev) | 596 | static int s3c2410_nand_remove(struct platform_device *pdev) |
@@ -524,9 +602,10 @@ static int s3c2410_nand_remove(struct platform_device *pdev) | |||
524 | if (info == NULL) | 602 | if (info == NULL) |
525 | return 0; | 603 | return 0; |
526 | 604 | ||
527 | /* first thing we need to do is release all our mtds | 605 | s3c2410_nand_cpufreq_deregister(info); |
528 | * and their partitions, then go through freeing the | 606 | |
529 | * resources used | 607 | /* Release all our mtds and their partitions, then go through |
608 | * freeing the resources used | ||
530 | */ | 609 | */ |
531 | 610 | ||
532 | if (info->mtds != NULL) { | 611 | if (info->mtds != NULL) { |
@@ -691,7 +770,8 @@ static void s3c2410_nand_update_chip(struct s3c2410_nand_info *info, | |||
691 | { | 770 | { |
692 | struct nand_chip *chip = &nmtd->chip; | 771 | struct nand_chip *chip = &nmtd->chip; |
693 | 772 | ||
694 | printk("%s: chip %p: %d\n", __func__, chip, chip->page_shift); | 773 | dev_dbg(info->device, "chip %p => page shift %d\n", |
774 | chip, chip->page_shift); | ||
695 | 775 | ||
696 | if (hardware_ecc) { | 776 | if (hardware_ecc) { |
697 | /* change the behaviour depending on wether we are using | 777 | /* change the behaviour depending on wether we are using |
@@ -784,7 +864,7 @@ static int s3c24xx_nand_probe(struct platform_device *pdev, | |||
784 | 864 | ||
785 | /* initialise the hardware */ | 865 | /* initialise the hardware */ |
786 | 866 | ||
787 | err = s3c2410_nand_inithw(info, pdev); | 867 | err = s3c2410_nand_inithw(info); |
788 | if (err != 0) | 868 | if (err != 0) |
789 | goto exit_error; | 869 | goto exit_error; |
790 | 870 | ||
@@ -827,6 +907,12 @@ static int s3c24xx_nand_probe(struct platform_device *pdev, | |||
827 | sets++; | 907 | sets++; |
828 | } | 908 | } |
829 | 909 | ||
910 | err = s3c2410_nand_cpufreq_register(info); | ||
911 | if (err < 0) { | ||
912 | dev_err(&pdev->dev, "failed to init cpufreq support\n"); | ||
913 | goto exit_error; | ||
914 | } | ||
915 | |||
830 | if (allow_clk_stop(info)) { | 916 | if (allow_clk_stop(info)) { |
831 | dev_info(&pdev->dev, "clock idle support enabled\n"); | 917 | dev_info(&pdev->dev, "clock idle support enabled\n"); |
832 | clk_disable(info->clk); | 918 | clk_disable(info->clk); |
@@ -874,7 +960,7 @@ static int s3c24xx_nand_resume(struct platform_device *dev) | |||
874 | 960 | ||
875 | if (info) { | 961 | if (info) { |
876 | clk_enable(info->clk); | 962 | clk_enable(info->clk); |
877 | s3c2410_nand_inithw(info, dev); | 963 | s3c2410_nand_inithw(info); |
878 | 964 | ||
879 | /* Restore the state of the nFCE line. */ | 965 | /* Restore the state of the nFCE line. */ |
880 | 966 | ||
diff --git a/drivers/mtd/nand/sharpsl.c b/drivers/mtd/nand/sharpsl.c index 033f8800b1e6..6dba2fb66ae5 100644 --- a/drivers/mtd/nand/sharpsl.c +++ b/drivers/mtd/nand/sharpsl.c | |||
@@ -3,8 +3,6 @@ | |||
3 | * | 3 | * |
4 | * Copyright (C) 2004 Richard Purdie | 4 | * Copyright (C) 2004 Richard Purdie |
5 | * | 5 | * |
6 | * $Id: sharpsl.c,v 1.7 2005/11/07 11:14:31 gleixner Exp $ | ||
7 | * | ||
8 | * Based on Sharp's NAND driver sharp_sl.c | 6 | * Based on Sharp's NAND driver sharp_sl.c |
9 | * | 7 | * |
10 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
diff --git a/drivers/mtd/nand/spia.c b/drivers/mtd/nand/spia.c index 1f6d429b1583..0cc6d0acb8fe 100644 --- a/drivers/mtd/nand/spia.c +++ b/drivers/mtd/nand/spia.c | |||
@@ -8,8 +8,6 @@ | |||
8 | * to controllines (due to change in nand.c) | 8 | * to controllines (due to change in nand.c) |
9 | * page_cache added | 9 | * page_cache added |
10 | * | 10 | * |
11 | * $Id: spia.c,v 1.25 2005/11/07 11:14:31 gleixner Exp $ | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
14 | * it under the terms of the GNU General Public License version 2 as | 12 | * it under the terms of the GNU General Public License version 2 as |
15 | * published by the Free Software Foundation. | 13 | * published by the Free Software Foundation. |
diff --git a/drivers/mtd/nand/toto.c b/drivers/mtd/nand/toto.c index f9e2d4a0ab8c..bbf492e6830d 100644 --- a/drivers/mtd/nand/toto.c +++ b/drivers/mtd/nand/toto.c | |||
@@ -14,8 +14,6 @@ | |||
14 | * Overview: | 14 | * Overview: |
15 | * This is a device driver for the NAND flash device found on the | 15 | * This is a device driver for the NAND flash device found on the |
16 | * TI fido board. It supports 32MiB and 64MiB cards | 16 | * TI fido board. It supports 32MiB and 64MiB cards |
17 | * | ||
18 | * $Id: toto.c,v 1.5 2005/11/07 11:14:31 gleixner Exp $ | ||
19 | */ | 17 | */ |
20 | 18 | ||
21 | #include <linux/slab.h> | 19 | #include <linux/slab.h> |
diff --git a/drivers/mtd/nand/ts7250.c b/drivers/mtd/nand/ts7250.c index f40081069ab2..807a72752eeb 100644 --- a/drivers/mtd/nand/ts7250.c +++ b/drivers/mtd/nand/ts7250.c | |||
@@ -9,8 +9,6 @@ | |||
9 | * Derived from drivers/mtd/nand/autcpu12.c | 9 | * Derived from drivers/mtd/nand/autcpu12.c |
10 | * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de) | 10 | * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de) |
11 | * | 11 | * |
12 | * $Id: ts7250.c,v 1.4 2004/12/30 22:02:07 joff Exp $ | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or modify | 12 | * This program is free software; you can redistribute it and/or modify |
15 | * it under the terms of the GNU General Public License version 2 as | 13 | * it under the terms of the GNU General Public License version 2 as |
16 | * published by the Free Software Foundation. | 14 | * published by the Free Software Foundation. |