linux/drivers/mtd/maps/tqm8xxl.c
<<
>>
Prefs
   1/*
   2 * Handle mapping of the flash memory access routines
   3 * on TQM8xxL based devices.
   4 *
   5 * based on rpxlite.c
   6 *
   7 * Copyright(C) 2001 Kirk Lee <kirk@hpc.ee.ntu.edu.tw>
   8 *
   9 * This code is GPLed
  10 *
  11 */
  12
  13/*
  14 * According to TQM8xxL hardware manual, TQM8xxL series have
  15 * following flash memory organisations:
  16 *      | capacity |    | chip type |   | bank0 |       | bank1 |
  17 *          2MiB           512Kx16        2MiB             0
  18 *          4MiB           1Mx16          4MiB             0
  19 *          8MiB           1Mx16          4MiB             4MiB
  20 * Thus, we choose CONFIG_MTD_CFI_I2 & CONFIG_MTD_CFI_B4 at
  21 * kernel configuration.
  22 */
  23#include <linux/module.h>
  24#include <linux/types.h>
  25#include <linux/kernel.h>
  26#include <linux/init.h>
  27#include <linux/slab.h>
  28
  29#include <linux/mtd/mtd.h>
  30#include <linux/mtd/map.h>
  31#include <linux/mtd/partitions.h>
  32
  33#include <asm/io.h>
  34
  35#define FLASH_ADDR 0x40000000
  36#define FLASH_SIZE 0x00800000
  37#define FLASH_BANK_MAX 4
  38
  39// trivial struct to describe partition information
  40struct mtd_part_def
  41{
  42        int nums;
  43        unsigned char *type;
  44        struct mtd_partition* mtd_part;
  45};
  46
  47//static struct mtd_info *mymtd;
  48static struct mtd_info* mtd_banks[FLASH_BANK_MAX];
  49static struct map_info* map_banks[FLASH_BANK_MAX];
  50static struct mtd_part_def part_banks[FLASH_BANK_MAX];
  51static unsigned long num_banks;
  52static void __iomem *start_scan_addr;
  53
  54/*
  55 * Here are partition information for all known TQM8xxL series devices.
  56 * See include/linux/mtd/partitions.h for definition of the mtd_partition
  57 * structure.
  58 *
  59 * The *_max_flash_size is the maximum possible mapped flash size which
  60 * is not necessarily the actual flash size.  It must correspond to the
  61 * value specified in the mapping definition defined by the
  62 * "struct map_desc *_io_desc" for the corresponding machine.
  63 */
  64
  65#ifdef CONFIG_MTD_PARTITIONS
  66/* Currently, TQM8xxL has upto 8MiB flash */
  67static unsigned long tqm8xxl_max_flash_size = 0x00800000;
  68
  69/* partition definition for first flash bank
  70 * (cf. "drivers/char/flash_config.c")
  71 */
  72static struct mtd_partition tqm8xxl_partitions[] = {
  73        {
  74          .name = "ppcboot",
  75          .offset = 0x00000000,
  76          .size = 0x00020000,           /* 128KB           */
  77          .mask_flags = MTD_WRITEABLE,  /* force read-only */
  78        },
  79        {
  80          .name = "kernel",             /* default kernel image */
  81          .offset = 0x00020000,
  82          .size = 0x000e0000,
  83          .mask_flags = MTD_WRITEABLE,  /* force read-only */
  84        },
  85        {
  86          .name = "user",
  87          .offset = 0x00100000,
  88          .size = 0x00100000,
  89        },
  90        {
  91          .name = "initrd",
  92          .offset = 0x00200000,
  93          .size = 0x00200000,
  94        }
  95};
  96/* partition definition for second flash bank */
  97static struct mtd_partition tqm8xxl_fs_partitions[] = {
  98        {
  99          .name = "cramfs",
 100          .offset = 0x00000000,
 101          .size = 0x00200000,
 102        },
 103        {
 104          .name = "jffs",
 105          .offset = 0x00200000,
 106          .size = 0x00200000,
 107          //.size = MTDPART_SIZ_FULL,
 108        }
 109};
 110#endif
 111
 112static int __init init_tqm_mtd(void)
 113{
 114        int idx = 0, ret = 0;
 115        unsigned long flash_addr, flash_size, mtd_size = 0;
 116        /* pointer to TQM8xxL board info data */
 117        bd_t *bd = (bd_t *)__res;
 118
 119        flash_addr = bd->bi_flashstart;
 120        flash_size = bd->bi_flashsize;
 121
 122        //request maximum flash size address space
 123        start_scan_addr = ioremap(flash_addr, flash_size);
 124        if (!start_scan_addr) {
 125                printk(KERN_WARNING "%s:Failed to ioremap address:0x%x\n", __func__, 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                printk(KERN_INFO "%s: chip probing count %d\n", __func__, idx);
 134
 135                map_banks[idx] = kzalloc(sizeof(struct map_info), GFP_KERNEL);
 136                if(map_banks[idx] == NULL) {
 137                        ret = -ENOMEM;
 138                        /* FIXME: What if some MTD devices were probed already? */
 139                        goto error_mem;
 140                }
 141
 142                map_banks[idx]->name = (char *)kmalloc(16, GFP_KERNEL);
 143
 144                if (!map_banks[idx]->name) {
 145                        ret = -ENOMEM;
 146                        /* FIXME: What if some MTD devices were probed already? */
 147                        goto error_mem;
 148                }
 149                sprintf(map_banks[idx]->name, "TQM8xxL%d", idx);
 150
 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 = start_scan_addr;
 157                map_banks[idx]->phys = flash_addr;
 158                /* FIXME: This looks utterly bogus, but I'm trying to
 159                   preserve the behaviour of the original (shown here)...
 160
 161                map_banks[idx]->map_priv_1 =
 162                start_scan_addr + ((idx > 0) ?
 163                (mtd_banks[idx-1] ? mtd_banks[idx-1]->size : 0) : 0);
 164                */
 165
 166                if (idx && mtd_banks[idx-1]) {
 167                        map_banks[idx]->virt += mtd_banks[idx-1]->size;
 168                        map_banks[idx]->phys += mtd_banks[idx-1]->size;
 169                }
 170
 171                //start to probe flash chips
 172                mtd_banks[idx] = do_map_probe("cfi_probe", map_banks[idx]);
 173
 174                if (mtd_banks[idx]) {
 175                        mtd_banks[idx]->owner = THIS_MODULE;
 176                        mtd_size += mtd_banks[idx]->size;
 177                        num_banks++;
 178
 179                        printk(KERN_INFO "%s: bank%d, name:%s, size:%dbytes \n", __func__, num_banks,
 180                        mtd_banks[idx]->name, mtd_banks[idx]->size);
 181                }
 182        }
 183
 184        /* no supported flash chips found */
 185        if (!num_banks) {
 186                printk(KERN_NOTICE "TQM8xxL: No support flash chips found!\n");
 187                ret = -ENXIO;
 188                goto error_mem;
 189        }
 190
 191#ifdef CONFIG_MTD_PARTITIONS
 192        /*
 193         * Select Static partition definitions
 194         */
 195        part_banks[0].mtd_part = tqm8xxl_partitions;
 196        part_banks[0].type = "Static image";
 197        part_banks[0].nums = ARRAY_SIZE(tqm8xxl_partitions);
 198
 199        part_banks[1].mtd_part = tqm8xxl_fs_partitions;
 200        part_banks[1].type = "Static file system";
 201        part_banks[1].nums = ARRAY_SIZE(tqm8xxl_fs_partitions);
 202
 203        for(idx = 0; idx < num_banks ; idx++) {
 204                if (part_banks[idx].nums == 0) {
 205                        printk(KERN_NOTICE "TQM flash%d: no partition info available, registering whole flash at once\n", idx);
 206                        add_mtd_device(mtd_banks[idx]);
 207                } else {
 208                        printk(KERN_NOTICE "TQM flash%d: Using %s partition definition\n",
 209                                        idx, part_banks[idx].type);
 210                        add_mtd_partitions(mtd_banks[idx], part_banks[idx].mtd_part,
 211                                                                part_banks[idx].nums);
 212                }
 213        }
 214#else
 215        printk(KERN_NOTICE "TQM flash: registering %d whole flash banks at once\n", num_banks);
 216        for(idx = 0 ; idx < num_banks ; idx++)
 217                add_mtd_device(mtd_banks[idx]);
 218#endif
 219        return 0;
 220error_mem:
 221        for(idx = 0 ; idx < FLASH_BANK_MAX ; idx++) {
 222                if(map_banks[idx] != NULL) {
 223                        kfree(map_banks[idx]->name);
 224                        map_banks[idx]->name = NULL;
 225                        kfree(map_banks[idx]);
 226                        map_banks[idx] = NULL;
 227                }
 228        }
 229error:
 230        iounmap(start_scan_addr);
 231        return ret;
 232}
 233
 234static void __exit cleanup_tqm_mtd(void)
 235{
 236        unsigned int idx = 0;
 237        for(idx = 0 ; idx < num_banks ; idx++) {
 238                /* destroy mtd_info previously allocated */
 239                if (mtd_banks[idx]) {
 240                        del_mtd_partitions(mtd_banks[idx]);
 241                        map_destroy(mtd_banks[idx]);
 242                }
 243                /* release map_info not used anymore */
 244                kfree(map_banks[idx]->name);
 245                kfree(map_banks[idx]);
 246        }
 247
 248        if (start_scan_addr) {
 249                iounmap(start_scan_addr);
 250                start_scan_addr = 0;
 251        }
 252}
 253
 254module_init(init_tqm_mtd);
 255module_exit(cleanup_tqm_mtd);
 256
 257MODULE_LICENSE("GPL");
 258MODULE_AUTHOR("Kirk Lee <kirk@hpc.ee.ntu.edu.tw>");
 259MODULE_DESCRIPTION("MTD map driver for TQM8xxL boards");
 260