Merge branch 'for-linus' of git://git.o-hand.com/linux-rpurdie-leds
[linux-2.6] / 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] = kzalloc(sizeof(struct map_info), GFP_KERNEL);
136                 if (map_banks[idx] == NULL) {
137                         ret = -ENOMEM;
138                         goto error_mem;
139                 }
140                 map_banks[idx]->name = kzalloc(16, GFP_KERNEL);
141                 if (map_banks[idx]->name == NULL) {
142                         ret = -ENOMEM;
143                         goto error_mem;
144                 }
145
146                 sprintf(map_banks[idx]->name, "TQM834x-%d", idx);
147                 map_banks[idx]->size = flash_size;
148                 map_banks[idx]->bankwidth = 4;
149
150                 simple_map_init(map_banks[idx]);
151
152                 map_banks[idx]->virt = (void __iomem *)
153                         (start_scan_addr + ((idx > 0) ?
154                         (mtd_banks[idx-1] ? mtd_banks[idx-1]->size : 0) : 0));
155                 map_banks[idx]->phys =
156                         flash_addr + ((idx > 0) ?
157                         (mtd_banks[idx-1] ? mtd_banks[idx-1]->size : 0) : 0);
158
159                 /* start to probe flash chips */
160                 mtd_banks[idx] = do_map_probe("cfi_probe", map_banks[idx]);
161                 if (mtd_banks[idx]) {
162                         mtd_banks[idx]->owner = THIS_MODULE;
163                         mtd_size += mtd_banks[idx]->size;
164                         num_banks++;
165                         pr_debug("%s: bank %ld, name: %s, size: %d bytes \n",
166                                  __FUNCTION__, num_banks,
167                                  mtd_banks[idx]->name, mtd_banks[idx]->size);
168                 }
169         }
170
171         /* no supported flash chips found */
172         if (!num_banks) {
173                 printk("TQM834x: No supported flash chips found!\n");
174                 ret = -ENXIO;
175                 goto error_mem;
176         }
177
178 #ifdef CONFIG_MTD_PARTITIONS
179         /*
180          * Select static partition definitions
181          */
182         n = ARRAY_SIZE(tqm834x_partitions_bank1);
183         part_banks[0].mtd_part  = tqm834x_partitions_bank1;
184         part_banks[0].type      = "static image bank1";
185         part_banks[0].nums      = n;
186
187         /* update last partition size to cover actual remaining space */
188         tqm834x_partitions_bank1[n - 1].size =
189                 mtd_banks[0]->size -
190                 tqm834x_partitions_bank1[n - 1].offset;
191
192         /* check if we have second bank? */
193         if (num_banks == 2) {
194                 n = ARRAY_SIZE(tqm834x_partitions_bank2);
195                 part_banks[1].mtd_part  = tqm834x_partitions_bank2;
196                 part_banks[1].type      = "static image bank2";
197                 part_banks[1].nums      = n;
198
199                 /* update last partition size to cover actual remaining space */
200                 tqm834x_partitions_bank2[n - 1].size =
201                         mtd_banks[1]->size -
202                         tqm834x_partitions_bank2[n - 1].offset;
203         }
204
205         for(idx = 0; idx < num_banks ; idx++) {
206 #ifdef CONFIG_MTD_CMDLINE_PARTS
207                 sprintf(mtdid, "%d", idx);
208                 n = parse_mtd_partitions(mtd_banks[idx],
209                                          part_probes,
210                                          &part_banks[idx].mtd_part,
211                                          0);
212                 pr_debug("%s: %d command line partitions on bank %s\n",
213                          __FUNCTION__, n, mtdid);
214                 if (n > 0) {
215                         part_banks[idx].type = "command line";
216                         part_banks[idx].nums = n;
217                 }
218 #endif  /* CONFIG_MTD_CMDLINE_PARTS */
219                 if (part_banks[idx].nums == 0) {
220                         printk(KERN_NOTICE
221                                "TQM834x flash bank %d: no partition info "
222                                "available, registering whole device\n", idx);
223                         add_mtd_device(mtd_banks[idx]);
224                 } else {
225                         printk(KERN_NOTICE
226                                "TQM834x flash bank %d: Using %s partition "
227                                "definition\n", idx, part_banks[idx].type);
228                         add_mtd_partitions(mtd_banks[idx],
229                                            part_banks[idx].mtd_part,
230                                            part_banks[idx].nums);
231                 }
232         }
233 #else   /* ! CONFIG_MTD_PARTITIONS */
234         printk(KERN_NOTICE "TQM834x flash: registering %d flash banks "
235                         "at once\n", num_banks);
236
237         for(idx = 0 ; idx < num_banks ; idx++)
238                 add_mtd_device(mtd_banks[idx]);
239
240 #endif  /* CONFIG_MTD_PARTITIONS */
241
242         return 0;
243 error_mem:
244         for (idx = 0 ; idx < FLASH_BANK_MAX ; idx++) {
245                 if (map_banks[idx] != NULL) {
246                         if (map_banks[idx]->name != NULL) {
247                                 kfree(map_banks[idx]->name);
248                                 map_banks[idx]->name = NULL;
249                         }
250                         kfree(map_banks[idx]);
251                         map_banks[idx] = NULL;
252                 }
253         }
254
255         iounmap((void *)start_scan_addr);
256
257         return ret;
258 }
259
260 static void __exit cleanup_tqm834x_mtd(void)
261 {
262         unsigned int idx = 0;
263         for(idx = 0 ; idx < num_banks ; idx++) {
264                 /* destroy mtd_info previously allocated */
265                 if (mtd_banks[idx]) {
266                         del_mtd_partitions(mtd_banks[idx]);
267                         map_destroy(mtd_banks[idx]);
268                 }
269
270                 /* release map_info not used anymore */
271                 kfree(map_banks[idx]->name);
272                 kfree(map_banks[idx]);
273         }
274
275         if (start_scan_addr) {
276                 iounmap((void *)start_scan_addr);
277                 start_scan_addr = 0;
278         }
279 }
280
281 module_init(init_tqm834x_mtd);
282 module_exit(cleanup_tqm834x_mtd);
283
284 MODULE_LICENSE("GPL");
285 MODULE_AUTHOR("Wolfgang Denk <wd@denx.de>");
286 MODULE_DESCRIPTION("MTD map driver for TQM834x boards");