linux/drivers/mtd/maps/ceiva.c
<<
>>
Prefs
   1/*
   2 * Ceiva flash memory driver.
   3 * Copyright (C) 2002 Rob Scott <rscott@mtrob.fdns.net>
   4 *
   5 * Note: this driver supports jedec compatible devices. Modification
   6 * for CFI compatible devices should be straight forward: change
   7 * jedec_probe to cfi_probe.
   8 *
   9 * Based on: sa1100-flash.c, which has the following copyright:
  10 * Flash memory access on SA11x0 based devices
  11 *
  12 * (C) 2000 Nicolas Pitre <nico@fluxnic.net>
  13 *
  14 */
  15
  16#include <linux/module.h>
  17#include <linux/types.h>
  18#include <linux/ioport.h>
  19#include <linux/kernel.h>
  20#include <linux/init.h>
  21#include <linux/slab.h>
  22
  23#include <linux/mtd/mtd.h>
  24#include <linux/mtd/map.h>
  25#include <linux/mtd/partitions.h>
  26#include <linux/mtd/concat.h>
  27
  28#include <mach/hardware.h>
  29#include <asm/mach-types.h>
  30#include <asm/io.h>
  31#include <asm/sizes.h>
  32
  33/*
  34 * This isn't complete yet, so...
  35 */
  36#define CONFIG_MTD_CEIVA_STATICMAP
  37
  38#ifdef CONFIG_MTD_CEIVA_STATICMAP
  39/*
  40 * See include/linux/mtd/partitions.h for definition of the mtd_partition
  41 * structure.
  42 *
  43 * Please note:
  44 *  1. The flash size given should be the largest flash size that can
  45 *     be accommodated.
  46 *
  47 *  2. The bus width must defined in clps_setup_flash.
  48 *
  49 * The MTD layer will detect flash chip aliasing and reduce the size of
  50 * the map accordingly.
  51 *
  52 */
  53
  54#ifdef CONFIG_ARCH_CEIVA
  55/* Flash / Partition sizing */
  56/* For the 28F8003, we use the block mapping to calcuate the sizes */
  57#define MAX_SIZE_KiB                  (16 + 8 + 8 + 96 + (7*128))
  58#define BOOT_PARTITION_SIZE_KiB       (16)
  59#define PARAMS_PARTITION_SIZE_KiB     (8)
  60#define KERNEL_PARTITION_SIZE_KiB     (4*128)
  61/* Use both remaining portion of first flash, and all of second flash */
  62#define ROOT_PARTITION_SIZE_KiB       (3*128) + (8*128)
  63
  64static struct mtd_partition ceiva_partitions[] = {
  65        {
  66                .name = "Ceiva BOOT partition",
  67                .size   = BOOT_PARTITION_SIZE_KiB*1024,
  68                .offset = 0,
  69
  70        },{
  71                .name = "Ceiva parameters partition",
  72                .size   = PARAMS_PARTITION_SIZE_KiB*1024,
  73                .offset = (16 + 8) * 1024,
  74        },{
  75                .name = "Ceiva kernel partition",
  76                .size = (KERNEL_PARTITION_SIZE_KiB)*1024,
  77                .offset = 0x20000,
  78
  79        },{
  80                .name = "Ceiva root filesystem partition",
  81                .offset = MTDPART_OFS_APPEND,
  82                .size = (ROOT_PARTITION_SIZE_KiB)*1024,
  83        }
  84};
  85#endif
  86
  87static int __init clps_static_partitions(struct mtd_partition **parts)
  88{
  89        int nb_parts = 0;
  90
  91#ifdef CONFIG_ARCH_CEIVA
  92        if (machine_is_ceiva()) {
  93                *parts       = ceiva_partitions;
  94                nb_parts     = ARRAY_SIZE(ceiva_partitions);
  95        }
  96#endif
  97        return nb_parts;
  98}
  99#endif
 100
 101struct clps_info {
 102        unsigned long base;
 103        unsigned long size;
 104        int width;
 105        void *vbase;
 106        struct map_info *map;
 107        struct mtd_info *mtd;
 108        struct resource *res;
 109};
 110
 111#define NR_SUBMTD 4
 112
 113static struct clps_info info[NR_SUBMTD];
 114
 115static int __init clps_setup_mtd(struct clps_info *clps, int nr, struct mtd_info **rmtd)
 116{
 117        struct mtd_info *subdev[nr];
 118        struct map_info *maps;
 119        int i, found = 0, ret = 0;
 120
 121        /*
 122         * Allocate the map_info structs in one go.
 123         */
 124        maps = kzalloc(sizeof(struct map_info) * nr, GFP_KERNEL);
 125        if (!maps)
 126                return -ENOMEM;
 127        /*
 128         * Claim and then map the memory regions.
 129         */
 130        for (i = 0; i < nr; i++) {
 131                if (clps[i].base == (unsigned long)-1)
 132                        break;
 133
 134                clps[i].res = request_mem_region(clps[i].base, clps[i].size, "clps flash");
 135                if (!clps[i].res) {
 136                        ret = -EBUSY;
 137                        break;
 138                }
 139
 140                clps[i].map = maps + i;
 141
 142                clps[i].map->name = "clps flash";
 143                clps[i].map->phys = clps[i].base;
 144
 145                clps[i].vbase = ioremap(clps[i].base, clps[i].size);
 146                if (!clps[i].vbase) {
 147                        ret = -ENOMEM;
 148                        break;
 149                }
 150
 151                clps[i].map->virt = (void __iomem *)clps[i].vbase;
 152                clps[i].map->bankwidth = clps[i].width;
 153                clps[i].map->size = clps[i].size;
 154
 155                simple_map_init(&clps[i].map);
 156
 157                clps[i].mtd = do_map_probe("jedec_probe", clps[i].map);
 158                if (clps[i].mtd == NULL) {
 159                        ret = -ENXIO;
 160                        break;
 161                }
 162                clps[i].mtd->owner = THIS_MODULE;
 163                subdev[i] = clps[i].mtd;
 164
 165                printk(KERN_INFO "clps flash: JEDEC device at 0x%08lx, %dMiB, "
 166                        "%d-bit\n", clps[i].base, clps[i].mtd->size >> 20,
 167                        clps[i].width * 8);
 168                found += 1;
 169        }
 170
 171        /*
 172         * ENXIO is special.  It means we didn't find a chip when
 173         * we probed.  We need to tear down the mapping, free the
 174         * resource and mark it as such.
 175         */
 176        if (ret == -ENXIO) {
 177                iounmap(clps[i].vbase);
 178                clps[i].vbase = NULL;
 179                release_resource(clps[i].res);
 180                clps[i].res = NULL;
 181        }
 182
 183        /*
 184         * If we found one device, don't bother with concat support.
 185         * If we found multiple devices, use concat if we have it
 186         * available, otherwise fail.
 187         */
 188        if (ret == 0 || ret == -ENXIO) {
 189                if (found == 1) {
 190                        *rmtd = subdev[0];
 191                        ret = 0;
 192                } else if (found > 1) {
 193                        /*
 194                         * We detected multiple devices.  Concatenate
 195                         * them together.
 196                         */
 197                        *rmtd = mtd_concat_create(subdev, found,
 198                                                  "clps flash");
 199                        if (*rmtd == NULL)
 200                                ret = -ENXIO;
 201                }
 202        }
 203
 204        /*
 205         * If we failed, clean up.
 206         */
 207        if (ret) {
 208                do {
 209                        if (clps[i].mtd)
 210                                map_destroy(clps[i].mtd);
 211                        if (clps[i].vbase)
 212                                iounmap(clps[i].vbase);
 213                        if (clps[i].res)
 214                                release_resource(clps[i].res);
 215                } while (i--);
 216
 217                kfree(maps);
 218        }
 219
 220        return ret;
 221}
 222
 223static void __exit clps_destroy_mtd(struct clps_info *clps, struct mtd_info *mtd)
 224{
 225        int i;
 226
 227        del_mtd_partitions(mtd);
 228
 229        if (mtd != clps[0].mtd)
 230                mtd_concat_destroy(mtd);
 231
 232        for (i = NR_SUBMTD; i >= 0; i--) {
 233                if (clps[i].mtd)
 234                        map_destroy(clps[i].mtd);
 235                if (clps[i].vbase)
 236                        iounmap(clps[i].vbase);
 237                if (clps[i].res)
 238                        release_resource(clps[i].res);
 239        }
 240        kfree(clps[0].map);
 241}
 242
 243/*
 244 * We define the memory space, size, and width for the flash memory
 245 * space here.
 246 */
 247
 248static int __init clps_setup_flash(void)
 249{
 250        int nr = 0;
 251
 252#ifdef CONFIG_ARCH_CEIVA
 253        if (machine_is_ceiva()) {
 254                info[0].base = CS0_PHYS_BASE;
 255                info[0].size = SZ_32M;
 256                info[0].width = CEIVA_FLASH_WIDTH;
 257                info[1].base = CS1_PHYS_BASE;
 258                info[1].size = SZ_32M;
 259                info[1].width = CEIVA_FLASH_WIDTH;
 260                nr = 2;
 261        }
 262#endif
 263        return nr;
 264}
 265
 266static struct mtd_partition *parsed_parts;
 267static const char *probes[] = { "cmdlinepart", "RedBoot", NULL };
 268
 269static void __init clps_locate_partitions(struct mtd_info *mtd)
 270{
 271        const char *part_type = NULL;
 272        int nr_parts = 0;
 273        do {
 274                /*
 275                 * Partition selection stuff.
 276                 */
 277                nr_parts = parse_mtd_partitions(mtd, probes, &parsed_parts, 0);
 278                if (nr_parts > 0) {
 279                        part_type = "command line";
 280                        break;
 281                }
 282#ifdef CONFIG_MTD_CEIVA_STATICMAP
 283                nr_parts = clps_static_partitions(&parsed_parts);
 284                if (nr_parts > 0) {
 285                        part_type = "static";
 286                        break;
 287                }
 288                printk("found: %d partitions\n", nr_parts);
 289#endif
 290        } while (0);
 291
 292        if (nr_parts == 0) {
 293                printk(KERN_NOTICE "clps flash: no partition info "
 294                        "available, registering whole flash\n");
 295                add_mtd_device(mtd);
 296        } else {
 297                printk(KERN_NOTICE "clps flash: using %s partition "
 298                        "definition\n", part_type);
 299                add_mtd_partitions(mtd, parsed_parts, nr_parts);
 300        }
 301
 302        /* Always succeeds. */
 303}
 304
 305static void __exit clps_destroy_partitions(void)
 306{
 307        kfree(parsed_parts);
 308}
 309
 310static struct mtd_info *mymtd;
 311
 312static int __init clps_mtd_init(void)
 313{
 314        int ret;
 315        int nr;
 316
 317        nr = clps_setup_flash();
 318        if (nr < 0)
 319                return nr;
 320
 321        ret = clps_setup_mtd(info, nr, &mymtd);
 322        if (ret)
 323                return ret;
 324
 325        clps_locate_partitions(mymtd);
 326
 327        return 0;
 328}
 329
 330static void __exit clps_mtd_cleanup(void)
 331{
 332        clps_destroy_mtd(info, mymtd);
 333        clps_destroy_partitions();
 334}
 335
 336module_init(clps_mtd_init);
 337module_exit(clps_mtd_cleanup);
 338
 339MODULE_AUTHOR("Rob Scott");
 340MODULE_DESCRIPTION("Cirrus Logic JEDEC map driver");
 341MODULE_LICENSE("GPL");
 342