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 accomodated.
  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 remaing 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#ifdef CONFIG_MTD_CONCAT
 198                        *rmtd = mtd_concat_create(subdev, found,
 199                                                  "clps flash");
 200                        if (*rmtd == NULL)
 201                                ret = -ENXIO;
 202#else
 203                        printk(KERN_ERR "clps flash: multiple devices "
 204                               "found but MTD concat support disabled.\n");
 205                        ret = -ENXIO;
 206#endif
 207                }
 208        }
 209
 210        /*
 211         * If we failed, clean up.
 212         */
 213        if (ret) {
 214                do {
 215                        if (clps[i].mtd)
 216                                map_destroy(clps[i].mtd);
 217                        if (clps[i].vbase)
 218                                iounmap(clps[i].vbase);
 219                        if (clps[i].res)
 220                                release_resource(clps[i].res);
 221                } while (i--);
 222
 223                kfree(maps);
 224        }
 225
 226        return ret;
 227}
 228
 229static void __exit clps_destroy_mtd(struct clps_info *clps, struct mtd_info *mtd)
 230{
 231        int i;
 232
 233        del_mtd_partitions(mtd);
 234
 235        if (mtd != clps[0].mtd)
 236                mtd_concat_destroy(mtd);
 237
 238        for (i = NR_SUBMTD; i >= 0; i--) {
 239                if (clps[i].mtd)
 240                        map_destroy(clps[i].mtd);
 241                if (clps[i].vbase)
 242                        iounmap(clps[i].vbase);
 243                if (clps[i].res)
 244                        release_resource(clps[i].res);
 245        }
 246        kfree(clps[0].map);
 247}
 248
 249/*
 250 * We define the memory space, size, and width for the flash memory
 251 * space here.
 252 */
 253
 254static int __init clps_setup_flash(void)
 255{
 256        int nr = 0;
 257
 258#ifdef CONFIG_ARCH_CEIVA
 259        if (machine_is_ceiva()) {
 260                info[0].base = CS0_PHYS_BASE;
 261                info[0].size = SZ_32M;
 262                info[0].width = CEIVA_FLASH_WIDTH;
 263                info[1].base = CS1_PHYS_BASE;
 264                info[1].size = SZ_32M;
 265                info[1].width = CEIVA_FLASH_WIDTH;
 266                nr = 2;
 267        }
 268#endif
 269        return nr;
 270}
 271
 272static struct mtd_partition *parsed_parts;
 273static const char *probes[] = { "cmdlinepart", "RedBoot", NULL };
 274
 275static void __init clps_locate_partitions(struct mtd_info *mtd)
 276{
 277        const char *part_type = NULL;
 278        int nr_parts = 0;
 279        do {
 280                /*
 281                 * Partition selection stuff.
 282                 */
 283                nr_parts = parse_mtd_partitions(mtd, probes, &parsed_parts, 0);
 284                if (nr_parts > 0) {
 285                        part_type = "command line";
 286                        break;
 287                }
 288#ifdef CONFIG_MTD_CEIVA_STATICMAP
 289                nr_parts = clps_static_partitions(&parsed_parts);
 290                if (nr_parts > 0) {
 291                        part_type = "static";
 292                        break;
 293                }
 294                printk("found: %d partitions\n", nr_parts);
 295#endif
 296        } while (0);
 297
 298        if (nr_parts == 0) {
 299                printk(KERN_NOTICE "clps flash: no partition info "
 300                        "available, registering whole flash\n");
 301                add_mtd_device(mtd);
 302        } else {
 303                printk(KERN_NOTICE "clps flash: using %s partition "
 304                        "definition\n", part_type);
 305                add_mtd_partitions(mtd, parsed_parts, nr_parts);
 306        }
 307
 308        /* Always succeeds. */
 309}
 310
 311static void __exit clps_destroy_partitions(void)
 312{
 313        kfree(parsed_parts);
 314}
 315
 316static struct mtd_info *mymtd;
 317
 318static int __init clps_mtd_init(void)
 319{
 320        int ret;
 321        int nr;
 322
 323        nr = clps_setup_flash();
 324        if (nr < 0)
 325                return nr;
 326
 327        ret = clps_setup_mtd(info, nr, &mymtd);
 328        if (ret)
 329                return ret;
 330
 331        clps_locate_partitions(mymtd);
 332
 333        return 0;
 334}
 335
 336static void __exit clps_mtd_cleanup(void)
 337{
 338        clps_destroy_mtd(info, mymtd);
 339        clps_destroy_partitions();
 340}
 341
 342module_init(clps_mtd_init);
 343module_exit(clps_mtd_cleanup);
 344
 345MODULE_AUTHOR("Rob Scott");
 346MODULE_DESCRIPTION("Cirrus Logic JEDEC map driver");
 347MODULE_LICENSE("GPL");
 348