diff options
Diffstat (limited to 'drivers/mtd/nand/sharpsl.c')
-rwxr-xr-x | drivers/mtd/nand/sharpsl.c | 260 |
1 files changed, 260 insertions, 0 deletions
diff --git a/drivers/mtd/nand/sharpsl.c b/drivers/mtd/nand/sharpsl.c new file mode 100755 index 000000000000..29572793334c --- /dev/null +++ b/drivers/mtd/nand/sharpsl.c | |||
@@ -0,0 +1,260 @@ | |||
1 | /* | ||
2 | * drivers/mtd/nand/sharpsl.c | ||
3 | * | ||
4 | * Copyright (C) 2004 Richard Purdie | ||
5 | * | ||
6 | * $Id: sharpsl.c,v 1.3 2005/01/03 14:53:50 rpurdie Exp $ | ||
7 | * | ||
8 | * Based on Sharp's NAND driver sharp_sl.c | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | */ | ||
15 | |||
16 | #include <linux/genhd.h> | ||
17 | #include <linux/slab.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/delay.h> | ||
20 | #include <linux/mtd/mtd.h> | ||
21 | #include <linux/mtd/nand.h> | ||
22 | #include <linux/mtd/nand_ecc.h> | ||
23 | #include <linux/mtd/partitions.h> | ||
24 | #include <linux/interrupt.h> | ||
25 | #include <asm/io.h> | ||
26 | #include <asm/hardware.h> | ||
27 | #include <asm/mach-types.h> | ||
28 | |||
29 | static void __iomem *sharpsl_io_base; | ||
30 | static int sharpsl_phys_base = 0x0C000000; | ||
31 | |||
32 | /* register offset */ | ||
33 | #define ECCLPLB sharpsl_io_base+0x00 /* line parity 7 - 0 bit */ | ||
34 | #define ECCLPUB sharpsl_io_base+0x04 /* line parity 15 - 8 bit */ | ||
35 | #define ECCCP sharpsl_io_base+0x08 /* column parity 5 - 0 bit */ | ||
36 | #define ECCCNTR sharpsl_io_base+0x0C /* ECC byte counter */ | ||
37 | #define ECCCLRR sharpsl_io_base+0x10 /* cleare ECC */ | ||
38 | #define FLASHIO sharpsl_io_base+0x14 /* Flash I/O */ | ||
39 | #define FLASHCTL sharpsl_io_base+0x18 /* Flash Control */ | ||
40 | |||
41 | /* Flash control bit */ | ||
42 | #define FLRYBY (1 << 5) | ||
43 | #define FLCE1 (1 << 4) | ||
44 | #define FLWP (1 << 3) | ||
45 | #define FLALE (1 << 2) | ||
46 | #define FLCLE (1 << 1) | ||
47 | #define FLCE0 (1 << 0) | ||
48 | |||
49 | |||
50 | /* | ||
51 | * MTD structure for SharpSL | ||
52 | */ | ||
53 | static struct mtd_info *sharpsl_mtd = NULL; | ||
54 | |||
55 | /* | ||
56 | * Define partitions for flash device | ||
57 | */ | ||
58 | #define DEFAULT_NUM_PARTITIONS 3 | ||
59 | |||
60 | static int nr_partitions; | ||
61 | static struct mtd_partition sharpsl_nand_default_partition_info[] = { | ||
62 | { | ||
63 | .name = "System Area", | ||
64 | .offset = 0, | ||
65 | .size = 7 * 1024 * 1024, | ||
66 | }, | ||
67 | { | ||
68 | .name = "Root Filesystem", | ||
69 | .offset = 7 * 1024 * 1024, | ||
70 | .size = 30 * 1024 * 1024, | ||
71 | }, | ||
72 | { | ||
73 | .name = "Home Filesystem", | ||
74 | .offset = MTDPART_OFS_APPEND , | ||
75 | .size = MTDPART_SIZ_FULL , | ||
76 | }, | ||
77 | }; | ||
78 | |||
79 | /* | ||
80 | * hardware specific access to control-lines | ||
81 | */ | ||
82 | static void | ||
83 | sharpsl_nand_hwcontrol(struct mtd_info* mtd, int cmd) | ||
84 | { | ||
85 | switch (cmd) { | ||
86 | case NAND_CTL_SETCLE: | ||
87 | writeb(readb(FLASHCTL) | FLCLE, FLASHCTL); | ||
88 | break; | ||
89 | case NAND_CTL_CLRCLE: | ||
90 | writeb(readb(FLASHCTL) & ~FLCLE, FLASHCTL); | ||
91 | break; | ||
92 | |||
93 | case NAND_CTL_SETALE: | ||
94 | writeb(readb(FLASHCTL) | FLALE, FLASHCTL); | ||
95 | break; | ||
96 | case NAND_CTL_CLRALE: | ||
97 | writeb(readb(FLASHCTL) & ~FLALE, FLASHCTL); | ||
98 | break; | ||
99 | |||
100 | case NAND_CTL_SETNCE: | ||
101 | writeb(readb(FLASHCTL) & ~(FLCE0|FLCE1), FLASHCTL); | ||
102 | break; | ||
103 | case NAND_CTL_CLRNCE: | ||
104 | writeb(readb(FLASHCTL) | (FLCE0|FLCE1), FLASHCTL); | ||
105 | break; | ||
106 | } | ||
107 | } | ||
108 | |||
109 | static uint8_t scan_ff_pattern[] = { 0xff, 0xff }; | ||
110 | |||
111 | static struct nand_bbt_descr sharpsl_bbt = { | ||
112 | .options = 0, | ||
113 | .offs = 4, | ||
114 | .len = 2, | ||
115 | .pattern = scan_ff_pattern | ||
116 | }; | ||
117 | |||
118 | static int | ||
119 | sharpsl_nand_dev_ready(struct mtd_info* mtd) | ||
120 | { | ||
121 | return !((readb(FLASHCTL) & FLRYBY) == 0); | ||
122 | } | ||
123 | |||
124 | static void | ||
125 | sharpsl_nand_enable_hwecc(struct mtd_info* mtd, int mode) | ||
126 | { | ||
127 | writeb(0 ,ECCCLRR); | ||
128 | } | ||
129 | |||
130 | static int | ||
131 | sharpsl_nand_calculate_ecc(struct mtd_info* mtd, const u_char* dat, | ||
132 | u_char* ecc_code) | ||
133 | { | ||
134 | ecc_code[0] = ~readb(ECCLPUB); | ||
135 | ecc_code[1] = ~readb(ECCLPLB); | ||
136 | ecc_code[2] = (~readb(ECCCP) << 2) | 0x03; | ||
137 | return readb(ECCCNTR) != 0; | ||
138 | } | ||
139 | |||
140 | |||
141 | #ifdef CONFIG_MTD_PARTITIONS | ||
142 | const char *part_probes[] = { "cmdlinepart", NULL }; | ||
143 | #endif | ||
144 | |||
145 | |||
146 | /* | ||
147 | * Main initialization routine | ||
148 | */ | ||
149 | int __init | ||
150 | sharpsl_nand_init(void) | ||
151 | { | ||
152 | struct nand_chip *this; | ||
153 | struct mtd_partition* sharpsl_partition_info; | ||
154 | int err = 0; | ||
155 | |||
156 | /* Allocate memory for MTD device structure and private data */ | ||
157 | sharpsl_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), | ||
158 | GFP_KERNEL); | ||
159 | if (!sharpsl_mtd) { | ||
160 | printk ("Unable to allocate SharpSL NAND MTD device structure.\n"); | ||
161 | return -ENOMEM; | ||
162 | } | ||
163 | |||
164 | /* map physical adress */ | ||
165 | sharpsl_io_base = ioremap(sharpsl_phys_base, 0x1000); | ||
166 | if(!sharpsl_io_base){ | ||
167 | printk("ioremap to access Sharp SL NAND chip failed\n"); | ||
168 | kfree(sharpsl_mtd); | ||
169 | return -EIO; | ||
170 | } | ||
171 | |||
172 | /* Get pointer to private data */ | ||
173 | this = (struct nand_chip *) (&sharpsl_mtd[1]); | ||
174 | |||
175 | /* Initialize structures */ | ||
176 | memset((char *) sharpsl_mtd, 0, sizeof(struct mtd_info)); | ||
177 | memset((char *) this, 0, sizeof(struct nand_chip)); | ||
178 | |||
179 | /* Link the private data with the MTD structure */ | ||
180 | sharpsl_mtd->priv = this; | ||
181 | |||
182 | /* | ||
183 | * PXA initialize | ||
184 | */ | ||
185 | writeb(readb(FLASHCTL) | FLWP, FLASHCTL); | ||
186 | |||
187 | /* Set address of NAND IO lines */ | ||
188 | this->IO_ADDR_R = FLASHIO; | ||
189 | this->IO_ADDR_W = FLASHIO; | ||
190 | /* Set address of hardware control function */ | ||
191 | this->hwcontrol = sharpsl_nand_hwcontrol; | ||
192 | this->dev_ready = sharpsl_nand_dev_ready; | ||
193 | /* 15 us command delay time */ | ||
194 | this->chip_delay = 15; | ||
195 | /* set eccmode using hardware ECC */ | ||
196 | this->eccmode = NAND_ECC_HW3_256; | ||
197 | this->enable_hwecc = sharpsl_nand_enable_hwecc; | ||
198 | this->calculate_ecc = sharpsl_nand_calculate_ecc; | ||
199 | this->correct_data = nand_correct_data; | ||
200 | this->badblock_pattern = &sharpsl_bbt; | ||
201 | |||
202 | /* Scan to find existence of the device */ | ||
203 | err=nand_scan(sharpsl_mtd,1); | ||
204 | if (err) { | ||
205 | iounmap(sharpsl_io_base); | ||
206 | kfree(sharpsl_mtd); | ||
207 | return err; | ||
208 | } | ||
209 | |||
210 | /* Register the partitions */ | ||
211 | sharpsl_mtd->name = "sharpsl-nand"; | ||
212 | nr_partitions = parse_mtd_partitions(sharpsl_mtd, part_probes, | ||
213 | &sharpsl_partition_info, 0); | ||
214 | |||
215 | if (nr_partitions <= 0) { | ||
216 | nr_partitions = DEFAULT_NUM_PARTITIONS; | ||
217 | sharpsl_partition_info = sharpsl_nand_default_partition_info; | ||
218 | if (machine_is_poodle()) { | ||
219 | sharpsl_partition_info[1].size=22 * 1024 * 1024; | ||
220 | } else if (machine_is_corgi() || machine_is_shepherd()) { | ||
221 | sharpsl_partition_info[1].size=25 * 1024 * 1024; | ||
222 | } else if (machine_is_husky()) { | ||
223 | sharpsl_partition_info[1].size=53 * 1024 * 1024; | ||
224 | } | ||
225 | } | ||
226 | |||
227 | if (machine_is_husky()) { | ||
228 | /* Need to use small eraseblock size for backward compatibility */ | ||
229 | sharpsl_mtd->flags |= MTD_NO_VIRTBLOCKS; | ||
230 | } | ||
231 | |||
232 | add_mtd_partitions(sharpsl_mtd, sharpsl_partition_info, nr_partitions); | ||
233 | |||
234 | /* Return happy */ | ||
235 | return 0; | ||
236 | } | ||
237 | module_init(sharpsl_nand_init); | ||
238 | |||
239 | /* | ||
240 | * Clean up routine | ||
241 | */ | ||
242 | #ifdef MODULE | ||
243 | static void __exit sharpsl_nand_cleanup(void) | ||
244 | { | ||
245 | struct nand_chip *this = (struct nand_chip *) &sharpsl_mtd[1]; | ||
246 | |||
247 | /* Release resources, unregister device */ | ||
248 | nand_release(sharpsl_mtd); | ||
249 | |||
250 | iounmap(sharpsl_io_base); | ||
251 | |||
252 | /* Free the MTD device structure */ | ||
253 | kfree(sharpsl_mtd); | ||
254 | } | ||
255 | module_exit(sharpsl_nand_cleanup); | ||
256 | #endif | ||
257 | |||
258 | MODULE_LICENSE("GPL"); | ||
259 | MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>"); | ||
260 | MODULE_DESCRIPTION("Device specific logic for NAND flash on Sharp SL-C7xx Series"); | ||