Merge to Fedora kernel-2.6.18-1.2224_FC5 patched with stable patch-2.6.18.1-vs2.0...
[linux-2.6.git] / drivers / mtd / maps / tqm834x.c
1 /*
2  * drivers/mtd/maps/tqm834x.c
3  *
4  * MTD mapping driver for TQM834x boards
5  *
6  * Copyright 2005 Wolfgang Denk, DENX Software Engineering, <wd@denx.de>.
7  *
8  * This file is licensed under the terms of the GNU General Public License
9  * version 2.  This program is licensed "as is" without any warranty of any
10  * kind, whether express or implied.
11  *
12  */
13
14 #include <linux/init.h>
15 #include <linux/module.h>
16 #include <linux/types.h>
17 #include <linux/kernel.h>
18 #include <linux/slab.h>
19 #include <asm/io.h>
20 #include <asm/ppcboot.h>
21
22 #include <linux/mtd/mtd.h>
23 #include <linux/mtd/map.h>
24 #include <linux/mtd/partitions.h>
25
26 #define FLASH_BANK_MAX  2
27
28 extern unsigned char __res[];
29
30 /* trivial struct to describe partition information */
31 struct mtd_part_def
32 {
33         int nums;
34         unsigned char *type;
35         struct mtd_partition* mtd_part;
36 };
37
38 static struct mtd_info* mtd_banks[FLASH_BANK_MAX];
39 static struct map_info* map_banks[FLASH_BANK_MAX];
40 static struct mtd_part_def part_banks[FLASH_BANK_MAX];
41
42 static unsigned long num_banks;
43 static unsigned long start_scan_addr;
44
45 #ifdef CONFIG_MTD_PARTITIONS
46 /*
47  * The following defines the partition layout of TQM834x boards.
48  *
49  * See include/linux/mtd/partitions.h for definition of the
50  * mtd_partition structure.
51  *
52  * Assume minimal initial size of 4 MiB per bank, will be updated
53  * later in init_tqm834x_mtd() routine.
54  */
55
56 /* Partition definition for the first flash bank which is always present. */
57 static struct mtd_partition tqm834x_partitions_bank1[] = {
58         {
59                 .name   = "u-boot",             /* u-boot firmware      */
60                 .offset = 0x00000000,
61                 .size   = 0x00040000,           /* 256 KiB              */
62                 /*mask_flags: MTD_WRITEABLE,     * force read-only      */
63         },
64         {
65                 .name   = "env",                /* u-boot environment   */
66                 .offset = 0x00040000,
67                 .size   = 0x00020000,           /* 128 KiB              */
68                 /*mask_flags: MTD_WRITEABLE,     * force read-only      */
69         },
70         {
71                 .name   = "kernel",             /* linux kernel image   */
72                 .offset = 0x00060000,
73                 .size   = 0x00100000,           /* 1 MiB                */
74                 /*mask_flags: MTD_WRITEABLE,     * force read-only      */
75         },
76         {
77                 .name   = "initrd",             /* ramdisk image        */
78                 .offset = 0x00160000,
79                 .size   = 0x00200000,           /* 2 MiB                */
80         },
81         {
82                 .name   = "user",               /* user data            */
83                 .offset = 0x00360000,
84                 .size   = 0x000a0000,           /* remaining space      */
85                 /* NOTE: this parttion size is re-calcated in           */
86                 /* init_tqm834x_mtd() to cover actual remaining space.  */
87         },
88 };
89
90 /* Partition definition for the second flash bank which may be present on some
91  * TQM834x boards.
92  */
93 static struct mtd_partition tqm834x_partitions_bank2[] = {
94         {
95                 .name   = "jffs2",              /* jffs2 filesystem     */
96                 .offset = 0x00000000,
97                 .size   = 0x00400000,           /* whole device         */
98                 /* NOTE: this parttion size is re-calcated in           */
99                 /* init_tqm834x_mtd() to cover actual device size.      */
100         },
101 };
102
103 #endif  /* CONFIG_MTD_PARTITIONS */
104
105 static int __init init_tqm834x_mtd(void)
106 {
107         int idx = 0, ret = 0;
108         unsigned long flash_addr, flash_size, mtd_size = 0;
109
110         /* pointer to TQM834x board info data */
111         bd_t *bd = (bd_t *)__res;
112 #ifdef CONFIG_MTD_CMDLINE_PARTS
113         int n;
114         char mtdid[4];
115         const char *part_probes[] = { "cmdlinepart", NULL };
116 #endif
117
118         flash_addr = bd->bi_flashstart;
119         flash_size = bd->bi_flashsize;
120
121         /* request maximum flash size address space */
122         start_scan_addr = (unsigned long)ioremap(flash_addr, flash_size);
123         if (!start_scan_addr) {
124                 printk("%s: Failed to ioremap address: 0x%lx\n",
125                        __FUNCTION__, flash_addr);
126                 return -EIO;
127         }
128
129         for(idx = 0 ; idx < FLASH_BANK_MAX ; idx++) {
130                 if (mtd_size >= flash_size)
131                         break;
132
133                 pr_debug("%s: chip probing count %d\n", __FUNCTION__, idx);
134
135                 map_banks[idx] =
136                         (struct map_info *)kmalloc(sizeof(struct map_info),
137                                                    GFP_KERNEL);
138                 if (map_banks[idx] == NULL) {
139                         ret = -ENOMEM;
140                         goto error_mem;
141                 }
142                 memset((void *)map_banks[idx], 0, sizeof(struct map_info));
143                 map_banks[idx]->name = (char *)kmalloc(16, GFP_KERNEL);
144                 if (map_banks[idx]->name == NULL) {
145                         ret = -ENOMEM;
146                         goto error_mem;
147                 }
148                 memset((void *)map_banks[idx]->name, 0, 16);
149
150                 sprintf(map_banks[idx]->name, "TQM834x-%d", idx);
151                 map_banks[idx]->size = flash_size;
152                 map_banks[idx]->bankwidth = 4;
153
154                 simple_map_init(map_banks[idx]);
155
156                 map_banks[idx]->virt = (void __iomem *)
157                         (start_scan_addr + ((idx > 0) ?
158                         (mtd_banks[idx-1] ? mtd_banks[idx-1]->size : 0) : 0));
159                 map_banks[idx]->phys =
160                         flash_addr + ((idx > 0) ?
161                         (mtd_banks[idx-1] ? mtd_banks[idx-1]->size : 0) : 0);
162
163                 /* start to probe flash chips */
164                 mtd_banks[idx] = do_map_probe("cfi_probe", map_banks[idx]);
165                 if (mtd_banks[idx]) {
166                         mtd_banks[idx]->owner = THIS_MODULE;
167                         mtd_size += mtd_banks[idx]->size;
168                         num_banks++;
169                         pr_debug("%s: bank %ld, name: %s, size: %d bytes \n",
170                                  __FUNCTION__, num_banks,
171                                  mtd_banks[idx]->name, mtd_banks[idx]->size);
172                 }
173         }
174
175         /* no supported flash chips found */
176         if (!num_banks) {
177                 printk("TQM834x: No supported flash chips found!\n");
178                 ret = -ENXIO;
179                 goto error_mem;
180         }
181
182 #ifdef CONFIG_MTD_PARTITIONS
183         /*
184          * Select static partition definitions
185          */
186         n = ARRAY_SIZE(tqm834x_partitions_bank1);
187         part_banks[0].mtd_part  = tqm834x_partitions_bank1;
188         part_banks[0].type      = "static image bank1";
189         part_banks[0].nums      = n;
190
191         /* update last partition size to cover actual remaining space */
192         tqm834x_partitions_bank1[n - 1].size =
193                 mtd_banks[0]->size -
194                 tqm834x_partitions_bank1[n - 1].offset;
195
196         /* check if we have second bank? */
197         if (num_banks == 2) {
198                 n = ARRAY_SIZE(tqm834x_partitions_bank2);
199                 part_banks[1].mtd_part  = tqm834x_partitions_bank2;
200                 part_banks[1].type      = "static image bank2";
201                 part_banks[1].nums      = n;
202
203                 /* update last partition size to cover actual remaining space */
204                 tqm834x_partitions_bank2[n - 1].size =
205                         mtd_banks[1]->size -
206                         tqm834x_partitions_bank2[n - 1].offset;
207         }
208
209         for(idx = 0; idx < num_banks ; idx++) {
210 #ifdef CONFIG_MTD_CMDLINE_PARTS
211                 sprintf(mtdid, "%d", idx);
212                 n = parse_mtd_partitions(mtd_banks[idx],
213                                          part_probes,
214                                          &part_banks[idx].mtd_part,
215                                          0);
216                 pr_debug("%s: %d command line partitions on bank %s\n",
217                          __FUNCTION__, n, mtdid);
218                 if (n > 0) {
219                         part_banks[idx].type = "command line";
220                         part_banks[idx].nums = n;
221                 }
222 #endif  /* CONFIG_MTD_CMDLINE_PARTS */
223                 if (part_banks[idx].nums == 0) {
224                         printk(KERN_NOTICE
225                                "TQM834x flash bank %d: no partition info "
226                                "available, registering whole device\n", idx);
227                         add_mtd_device(mtd_banks[idx]);
228                 } else {
229                         printk(KERN_NOTICE
230                                "TQM834x flash bank %d: Using %s partition "
231                                "definition\n", idx, part_banks[idx].type);
232                         add_mtd_partitions(mtd_banks[idx],
233                                            part_banks[idx].mtd_part,
234                                            part_banks[idx].nums);
235                 }
236         }
237 #else   /* ! CONFIG_MTD_PARTITIONS */
238         printk(KERN_NOTICE "TQM834x flash: registering %d flash banks "
239                         "at once\n", num_banks);
240
241         for(idx = 0 ; idx < num_banks ; idx++)
242                 add_mtd_device(mtd_banks[idx]);
243
244 #endif  /* CONFIG_MTD_PARTITIONS */
245
246         return 0;
247 error_mem:
248         for (idx = 0 ; idx < FLASH_BANK_MAX ; idx++) {
249                 if (map_banks[idx] != NULL) {
250                         if (map_banks[idx]->name != NULL) {
251                                 kfree(map_banks[idx]->name);
252                                 map_banks[idx]->name = NULL;
253                         }
254                         kfree(map_banks[idx]);
255                         map_banks[idx] = NULL;
256                 }
257         }
258
259         iounmap((void *)start_scan_addr);
260
261         return ret;
262 }
263
264 static void __exit cleanup_tqm834x_mtd(void)
265 {
266         unsigned int idx = 0;
267         for(idx = 0 ; idx < num_banks ; idx++) {
268                 /* destroy mtd_info previously allocated */
269                 if (mtd_banks[idx]) {
270                         del_mtd_partitions(mtd_banks[idx]);
271                         map_destroy(mtd_banks[idx]);
272                 }
273
274                 /* release map_info not used anymore */
275                 kfree(map_banks[idx]->name);
276                 kfree(map_banks[idx]);
277         }
278
279         if (start_scan_addr) {
280                 iounmap((void *)start_scan_addr);
281                 start_scan_addr = 0;
282         }
283 }
284
285 module_init(init_tqm834x_mtd);
286 module_exit(cleanup_tqm834x_mtd);
287
288 MODULE_LICENSE("GPL");
289 MODULE_AUTHOR("Wolfgang Denk <wd@denx.de>");
290 MODULE_DESCRIPTION("MTD map driver for TQM834x boards");