~ubuntu-branches/ubuntu/utopic/linux-ti-omap/utopic

« back to all changes in this revision

Viewing changes to drivers/mtd/maps/sa1100-flash.c

  • Committer: Bazaar Package Importer
  • Author(s): Amit Kucheria, Amit Kucheria
  • Date: 2010-03-10 02:28:15 UTC
  • Revision ID: james.westby@ubuntu.com-20100310022815-7sd3gwvn5kenaq33
Tags: 2.6.33-500.1
[ Amit Kucheria ]

* Initial release of a 2.6.33-based OMAP kernel
* UBUNTU: [Upstream] Fix omap 1-wire driver compilation
* UBUNTU: ubuntu: AppArmor -- update to mainline 2010-03-04

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Flash memory access on SA11x0 based devices
 
3
 *
 
4
 * (C) 2000 Nicolas Pitre <nico@fluxnic.net>
 
5
 */
 
6
#include <linux/module.h>
 
7
#include <linux/types.h>
 
8
#include <linux/ioport.h>
 
9
#include <linux/kernel.h>
 
10
#include <linux/init.h>
 
11
#include <linux/errno.h>
 
12
#include <linux/slab.h>
 
13
#include <linux/platform_device.h>
 
14
#include <linux/err.h>
 
15
#include <linux/io.h>
 
16
 
 
17
#include <linux/mtd/mtd.h>
 
18
#include <linux/mtd/map.h>
 
19
#include <linux/mtd/partitions.h>
 
20
#include <linux/mtd/concat.h>
 
21
 
 
22
#include <mach/hardware.h>
 
23
#include <asm/sizes.h>
 
24
#include <asm/mach/flash.h>
 
25
 
 
26
#if 0
 
27
/*
 
28
 * This is here for documentation purposes only - until these people
 
29
 * submit their machine types.  It will be gone January 2005.
 
30
 */
 
31
static struct mtd_partition consus_partitions[] = {
 
32
        {
 
33
                .name           = "Consus boot firmware",
 
34
                .offset         = 0,
 
35
                .size           = 0x00040000,
 
36
                .mask_flags     = MTD_WRITABLE, /* force read-only */
 
37
        }, {
 
38
                .name           = "Consus kernel",
 
39
                .offset         = 0x00040000,
 
40
                .size           = 0x00100000,
 
41
                .mask_flags     = 0,
 
42
        }, {
 
43
                .name           = "Consus disk",
 
44
                .offset         = 0x00140000,
 
45
                /* The rest (up to 16M) for jffs.  We could put 0 and
 
46
                   make it find the size automatically, but right now
 
47
                   i have 32 megs.  jffs will use all 32 megs if given
 
48
                   the chance, and this leads to horrible problems
 
49
                   when you try to re-flash the image because blob
 
50
                   won't erase the whole partition. */
 
51
                .size           = 0x01000000 - 0x00140000,
 
52
                .mask_flags     = 0,
 
53
        }, {
 
54
                /* this disk is a secondary disk, which can be used as
 
55
                   needed, for simplicity, make it the size of the other
 
56
                   consus partition, although realistically it could be
 
57
                   the remainder of the disk (depending on the file
 
58
                   system used) */
 
59
                 .name          = "Consus disk2",
 
60
                 .offset        = 0x01000000,
 
61
                 .size          = 0x01000000 - 0x00140000,
 
62
                 .mask_flags    = 0,
 
63
        }
 
64
};
 
65
 
 
66
/* Frodo has 2 x 16M 28F128J3A flash chips in bank 0: */
 
67
static struct mtd_partition frodo_partitions[] =
 
68
{
 
69
        {
 
70
                .name           = "bootloader",
 
71
                .size           = 0x00040000,
 
72
                .offset         = 0x00000000,
 
73
                .mask_flags     = MTD_WRITEABLE
 
74
        }, {
 
75
                .name           = "bootloader params",
 
76
                .size           = 0x00040000,
 
77
                .offset         = MTDPART_OFS_APPEND,
 
78
                .mask_flags     = MTD_WRITEABLE
 
79
        }, {
 
80
                .name           = "kernel",
 
81
                .size           = 0x00100000,
 
82
                .offset         = MTDPART_OFS_APPEND,
 
83
                .mask_flags     = MTD_WRITEABLE
 
84
        }, {
 
85
                .name           = "ramdisk",
 
86
                .size           = 0x00400000,
 
87
                .offset         = MTDPART_OFS_APPEND,
 
88
                .mask_flags     = MTD_WRITEABLE
 
89
        }, {
 
90
                .name           = "file system",
 
91
                .size           = MTDPART_SIZ_FULL,
 
92
                .offset         = MTDPART_OFS_APPEND
 
93
        }
 
94
};
 
95
 
 
96
static struct mtd_partition jornada56x_partitions[] = {
 
97
        {
 
98
                .name           = "bootldr",
 
99
                .size           = 0x00040000,
 
100
                .offset         = 0,
 
101
                .mask_flags     = MTD_WRITEABLE,
 
102
        }, {
 
103
                .name           = "rootfs",
 
104
                .size           = MTDPART_SIZ_FULL,
 
105
                .offset         = MTDPART_OFS_APPEND,
 
106
        }
 
107
};
 
108
 
 
109
static void jornada56x_set_vpp(int vpp)
 
110
{
 
111
        if (vpp)
 
112
                GPSR = GPIO_GPIO26;
 
113
        else
 
114
                GPCR = GPIO_GPIO26;
 
115
        GPDR |= GPIO_GPIO26;
 
116
}
 
117
 
 
118
/*
 
119
 * Machine        Phys          Size    set_vpp
 
120
 * Consus    : SA1100_CS0_PHYS SZ_32M
 
121
 * Frodo     : SA1100_CS0_PHYS SZ_32M
 
122
 * Jornada56x: SA1100_CS0_PHYS SZ_32M jornada56x_set_vpp
 
123
 */
 
124
#endif
 
125
 
 
126
struct sa_subdev_info {
 
127
        char name[16];
 
128
        struct map_info map;
 
129
        struct mtd_info *mtd;
 
130
        struct flash_platform_data *plat;
 
131
};
 
132
 
 
133
struct sa_info {
 
134
        struct mtd_partition    *parts;
 
135
        struct mtd_info         *mtd;
 
136
        int                     num_subdev;
 
137
        unsigned int            nr_parts;
 
138
        struct sa_subdev_info   subdev[0];
 
139
};
 
140
 
 
141
static void sa1100_set_vpp(struct map_info *map, int on)
 
142
{
 
143
        struct sa_subdev_info *subdev = container_of(map, struct sa_subdev_info, map);
 
144
        subdev->plat->set_vpp(on);
 
145
}
 
146
 
 
147
static void sa1100_destroy_subdev(struct sa_subdev_info *subdev)
 
148
{
 
149
        if (subdev->mtd)
 
150
                map_destroy(subdev->mtd);
 
151
        if (subdev->map.virt)
 
152
                iounmap(subdev->map.virt);
 
153
        release_mem_region(subdev->map.phys, subdev->map.size);
 
154
}
 
155
 
 
156
static int sa1100_probe_subdev(struct sa_subdev_info *subdev, struct resource *res)
 
157
{
 
158
        unsigned long phys;
 
159
        unsigned int size;
 
160
        int ret;
 
161
 
 
162
        phys = res->start;
 
163
        size = res->end - phys + 1;
 
164
 
 
165
        /*
 
166
         * Retrieve the bankwidth from the MSC registers.
 
167
         * We currently only implement CS0 and CS1 here.
 
168
         */
 
169
        switch (phys) {
 
170
        default:
 
171
                printk(KERN_WARNING "SA1100 flash: unknown base address "
 
172
                       "0x%08lx, assuming CS0\n", phys);
 
173
 
 
174
        case SA1100_CS0_PHYS:
 
175
                subdev->map.bankwidth = (MSC0 & MSC_RBW) ? 2 : 4;
 
176
                break;
 
177
 
 
178
        case SA1100_CS1_PHYS:
 
179
                subdev->map.bankwidth = ((MSC0 >> 16) & MSC_RBW) ? 2 : 4;
 
180
                break;
 
181
        }
 
182
 
 
183
        if (!request_mem_region(phys, size, subdev->name)) {
 
184
                ret = -EBUSY;
 
185
                goto out;
 
186
        }
 
187
 
 
188
        if (subdev->plat->set_vpp)
 
189
                subdev->map.set_vpp = sa1100_set_vpp;
 
190
 
 
191
        subdev->map.phys = phys;
 
192
        subdev->map.size = size;
 
193
        subdev->map.virt = ioremap(phys, size);
 
194
        if (!subdev->map.virt) {
 
195
                ret = -ENOMEM;
 
196
                goto err;
 
197
        }
 
198
 
 
199
        simple_map_init(&subdev->map);
 
200
 
 
201
        /*
 
202
         * Now let's probe for the actual flash.  Do it here since
 
203
         * specific machine settings might have been set above.
 
204
         */
 
205
        subdev->mtd = do_map_probe(subdev->plat->map_name, &subdev->map);
 
206
        if (subdev->mtd == NULL) {
 
207
                ret = -ENXIO;
 
208
                goto err;
 
209
        }
 
210
        subdev->mtd->owner = THIS_MODULE;
 
211
 
 
212
        printk(KERN_INFO "SA1100 flash: CFI device at 0x%08lx, %uMiB, %d-bit\n",
 
213
                phys, (unsigned)(subdev->mtd->size >> 20),
 
214
                subdev->map.bankwidth * 8);
 
215
 
 
216
        return 0;
 
217
 
 
218
 err:
 
219
        sa1100_destroy_subdev(subdev);
 
220
 out:
 
221
        return ret;
 
222
}
 
223
 
 
224
static void sa1100_destroy(struct sa_info *info, struct flash_platform_data *plat)
 
225
{
 
226
        int i;
 
227
 
 
228
        if (info->mtd) {
 
229
                if (info->nr_parts == 0)
 
230
                        del_mtd_device(info->mtd);
 
231
#ifdef CONFIG_MTD_PARTITIONS
 
232
                else
 
233
                        del_mtd_partitions(info->mtd);
 
234
#endif
 
235
#ifdef CONFIG_MTD_CONCAT
 
236
                if (info->mtd != info->subdev[0].mtd)
 
237
                        mtd_concat_destroy(info->mtd);
 
238
#endif
 
239
        }
 
240
 
 
241
        kfree(info->parts);
 
242
 
 
243
        for (i = info->num_subdev - 1; i >= 0; i--)
 
244
                sa1100_destroy_subdev(&info->subdev[i]);
 
245
        kfree(info);
 
246
 
 
247
        if (plat->exit)
 
248
                plat->exit();
 
249
}
 
250
 
 
251
static struct sa_info *__devinit
 
252
sa1100_setup_mtd(struct platform_device *pdev, struct flash_platform_data *plat)
 
253
{
 
254
        struct sa_info *info;
 
255
        int nr, size, i, ret = 0;
 
256
 
 
257
        /*
 
258
         * Count number of devices.
 
259
         */
 
260
        for (nr = 0; ; nr++)
 
261
                if (!platform_get_resource(pdev, IORESOURCE_MEM, nr))
 
262
                        break;
 
263
 
 
264
        if (nr == 0) {
 
265
                ret = -ENODEV;
 
266
                goto out;
 
267
        }
 
268
 
 
269
        size = sizeof(struct sa_info) + sizeof(struct sa_subdev_info) * nr;
 
270
 
 
271
        /*
 
272
         * Allocate the map_info structs in one go.
 
273
         */
 
274
        info = kzalloc(size, GFP_KERNEL);
 
275
        if (!info) {
 
276
                ret = -ENOMEM;
 
277
                goto out;
 
278
        }
 
279
 
 
280
        if (plat->init) {
 
281
                ret = plat->init();
 
282
                if (ret)
 
283
                        goto err;
 
284
        }
 
285
 
 
286
        /*
 
287
         * Claim and then map the memory regions.
 
288
         */
 
289
        for (i = 0; i < nr; i++) {
 
290
                struct sa_subdev_info *subdev = &info->subdev[i];
 
291
                struct resource *res;
 
292
 
 
293
                res = platform_get_resource(pdev, IORESOURCE_MEM, i);
 
294
                if (!res)
 
295
                        break;
 
296
 
 
297
                subdev->map.name = subdev->name;
 
298
                sprintf(subdev->name, "%s-%d", plat->name, i);
 
299
                subdev->plat = plat;
 
300
 
 
301
                ret = sa1100_probe_subdev(subdev, res);
 
302
                if (ret)
 
303
                        break;
 
304
        }
 
305
 
 
306
        info->num_subdev = i;
 
307
 
 
308
        /*
 
309
         * ENXIO is special.  It means we didn't find a chip when we probed.
 
310
         */
 
311
        if (ret != 0 && !(ret == -ENXIO && info->num_subdev > 0))
 
312
                goto err;
 
313
 
 
314
        /*
 
315
         * If we found one device, don't bother with concat support.  If
 
316
         * we found multiple devices, use concat if we have it available,
 
317
         * otherwise fail.  Either way, it'll be called "sa1100".
 
318
         */
 
319
        if (info->num_subdev == 1) {
 
320
                strcpy(info->subdev[0].name, plat->name);
 
321
                info->mtd = info->subdev[0].mtd;
 
322
                ret = 0;
 
323
        } else if (info->num_subdev > 1) {
 
324
#ifdef CONFIG_MTD_CONCAT
 
325
                struct mtd_info *cdev[nr];
 
326
                /*
 
327
                 * We detected multiple devices.  Concatenate them together.
 
328
                 */
 
329
                for (i = 0; i < info->num_subdev; i++)
 
330
                        cdev[i] = info->subdev[i].mtd;
 
331
 
 
332
                info->mtd = mtd_concat_create(cdev, info->num_subdev,
 
333
                                              plat->name);
 
334
                if (info->mtd == NULL)
 
335
                        ret = -ENXIO;
 
336
#else
 
337
                printk(KERN_ERR "SA1100 flash: multiple devices "
 
338
                       "found but MTD concat support disabled.\n");
 
339
                ret = -ENXIO;
 
340
#endif
 
341
        }
 
342
 
 
343
        if (ret == 0)
 
344
                return info;
 
345
 
 
346
 err:
 
347
        sa1100_destroy(info, plat);
 
348
 out:
 
349
        return ERR_PTR(ret);
 
350
}
 
351
 
 
352
static const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL };
 
353
 
 
354
static int __devinit sa1100_mtd_probe(struct platform_device *pdev)
 
355
{
 
356
        struct flash_platform_data *plat = pdev->dev.platform_data;
 
357
        struct mtd_partition *parts;
 
358
        const char *part_type = NULL;
 
359
        struct sa_info *info;
 
360
        int err, nr_parts = 0;
 
361
 
 
362
        if (!plat)
 
363
                return -ENODEV;
 
364
 
 
365
        info = sa1100_setup_mtd(pdev, plat);
 
366
        if (IS_ERR(info)) {
 
367
                err = PTR_ERR(info);
 
368
                goto out;
 
369
        }
 
370
 
 
371
        /*
 
372
         * Partition selection stuff.
 
373
         */
 
374
#ifdef CONFIG_MTD_PARTITIONS
 
375
        nr_parts = parse_mtd_partitions(info->mtd, part_probes, &parts, 0);
 
376
        if (nr_parts > 0) {
 
377
                info->parts = parts;
 
378
                part_type = "dynamic";
 
379
        } else
 
380
#endif
 
381
        {
 
382
                parts = plat->parts;
 
383
                nr_parts = plat->nr_parts;
 
384
                part_type = "static";
 
385
        }
 
386
 
 
387
        if (nr_parts == 0) {
 
388
                printk(KERN_NOTICE "SA1100 flash: no partition info "
 
389
                        "available, registering whole flash\n");
 
390
                add_mtd_device(info->mtd);
 
391
        } else {
 
392
                printk(KERN_NOTICE "SA1100 flash: using %s partition "
 
393
                        "definition\n", part_type);
 
394
                add_mtd_partitions(info->mtd, parts, nr_parts);
 
395
        }
 
396
 
 
397
        info->nr_parts = nr_parts;
 
398
 
 
399
        platform_set_drvdata(pdev, info);
 
400
        err = 0;
 
401
 
 
402
 out:
 
403
        return err;
 
404
}
 
405
 
 
406
static int __exit sa1100_mtd_remove(struct platform_device *pdev)
 
407
{
 
408
        struct sa_info *info = platform_get_drvdata(pdev);
 
409
        struct flash_platform_data *plat = pdev->dev.platform_data;
 
410
 
 
411
        platform_set_drvdata(pdev, NULL);
 
412
        sa1100_destroy(info, plat);
 
413
 
 
414
        return 0;
 
415
}
 
416
 
 
417
#ifdef CONFIG_PM
 
418
static void sa1100_mtd_shutdown(struct platform_device *dev)
 
419
{
 
420
        struct sa_info *info = platform_get_drvdata(dev);
 
421
        if (info && info->mtd->suspend(info->mtd) == 0)
 
422
                info->mtd->resume(info->mtd);
 
423
}
 
424
#else
 
425
#define sa1100_mtd_shutdown NULL
 
426
#endif
 
427
 
 
428
static struct platform_driver sa1100_mtd_driver = {
 
429
        .probe          = sa1100_mtd_probe,
 
430
        .remove         = __exit_p(sa1100_mtd_remove),
 
431
        .shutdown       = sa1100_mtd_shutdown,
 
432
        .driver         = {
 
433
                .name   = "sa1100-mtd",
 
434
                .owner  = THIS_MODULE,
 
435
        },
 
436
};
 
437
 
 
438
static int __init sa1100_mtd_init(void)
 
439
{
 
440
        return platform_driver_register(&sa1100_mtd_driver);
 
441
}
 
442
 
 
443
static void __exit sa1100_mtd_exit(void)
 
444
{
 
445
        platform_driver_unregister(&sa1100_mtd_driver);
 
446
}
 
447
 
 
448
module_init(sa1100_mtd_init);
 
449
module_exit(sa1100_mtd_exit);
 
450
 
 
451
MODULE_AUTHOR("Nicolas Pitre");
 
452
MODULE_DESCRIPTION("SA1100 CFI map driver");
 
453
MODULE_LICENSE("GPL");
 
454
MODULE_ALIAS("platform:sa1100-mtd");