How to read/write in flash memories (MTD)?

Garcia Jérémie GARCIAJ at 3il.fr
Fri Apr 1 18:40:53 EST 2005


Josh,

Your reply confirmed my feeling. So I've decided to use the MTD but with my own driver as I found in a tutorial. So I made the file (module) /drivers/mtd/maps/myBoardFlash.c in order to support my 2 flash memories. You can see the code below, but once again (sorry...) I have some questions and doubts on it. 
1- Is that driver correct for my case? 
2- Are those R/W routines are usable?
3- In our application we want to download source code and achievable code using Ethernet (so R/W operations). Do I need a filesystem for that as JFFS 2 ? 
4- Giving this driver, what is the process to use my R/W routines (if they are correct...) from the user space?


#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
#include <linux/mtd/partitions.h>
#include <linux/config.h>
#include <linux/version.h>
#include <asm/io.h>

static struct mtd_info *boot_flash;
static struct mtd_info *oper_flash;

/*************************************************/
/*                Mapping infos                  */
/*************************************************/

/* Map infos for the boot flash */
static struct map_info myboard_flash_boot_map = {
        .name      =   "MYBOARD boot flash",
        .size      =   BOARD_BOOT_FLASH_SIZE,
        .buswidth  =   1,
        .read8     =   myboard_flash_read8,
        .read16    =   myboard_flash_read16,
        .read32    =   myboard_flash_read32,
        .copy_from =   myboard_flash_copy_from,
        .write8    =   myboard_flash_write8,
        .write16   =   myboard_flash_write16,
        .write32   =   myboard_flash_write32,
        .copy_to   =   myboard_flash_copy_to
};


/* Map infos for the operationnal flash */
static struct map_info myboard_flash_oper_map = {
        .name      =   "MYBOARD oper flash",
        .size      =   BOARD_OPER_FLASH_SIZE,
        .buswidth  =   2,
        .read8     =   myboard_flash_read8,
        .read16    =   myboard_flash_read16,
        .read32    =   myboard_flash_read32,
        .copy_from =   myboard_flash_copy_from,
        .write8    =   myboard_flash_write8,
        .write16   =   myboard_flash_write16,
        .write32   =   myboard_flash_write32,
        .copy_to   =   myboard_flash_copy_to        
};


             
/*************************************************/
/*           Partitionning infos                 */
/*************************************************/

/* Boot flash partionning infos */
static struct mtd_partition myboard_flash_boot_partitions[] = {
        {
                .name =   "Boot flash partition",
                .offset = 0x0,
                .size =   BOARD_BOOT_FLASH_SIZE,
        }
};


/* Oper flash partionning infos */
static struct mtd_partition myboard_flash_oper_partitions[] = {
        {
                .name =   "Oper flash partition",  
                .offset = 0x0,
                .size =   BOARD_OPER_FLASH_SIZE,        
        }
};



/**************************************************/
/*          Read/Write routines                   */
/**************************************************/

__u8 myboard_flash_read8(struct map_info *map, unsigned long ofs)
{
  return __raw_readb(map->map_priv_1 + ofs);
}

__u16 myboard_flash_read16(struct map_info *map, unsigned long ofs)
{
  return __raw_readw(map->map_priv_1 + ofs);
}

__u32 myboard_flash_read32(struct map_info *map, unsigned long ofs)
{
  return __raw_readl(map->map_priv_1 + ofs);
}

void myboard_flash_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
{
  memcpy_fromio(to, map->map_priv_1 + from, len);
}

void myboard_flash_write8(struct map_info *map, __u8 d, unsigned long adr)
{
  __raw_writeb(d, map->map_priv_1 + adr);
  mb();
}

void myboard_flash_write16(struct map_info *map, __u16 d, unsigned long adr)
{
  __raw_writew(d, map->map_priv_1 + adr);
  mb();
}

void myboard_flash_write32(struct map_info *map, __u32 d, unsigned long adr)
{
  __raw_writel(d, map->map_priv_1 + adr);
  mb();
}



/**********************************************/
/*              Module Init                   */
/**********************************************/

int __init init_myboard_flash(void)                  map_info
{
    /*
     * Boot flash init
     */
 
    printk(KERN_NOTICE "myboard boot flash: %x at %x\n", BOARD_BOOT_FLASH_SIZE, MYBOARD_FLASH_BOOT_BASE);
    /* Obtain a virtual address for the physic one given ibn order to perform R/W operations */
    myboard_flash_boot_map.map_priv_1 = (unsigned long)ioremap(MYBOARD_FLASH_BOOT_BASE, BOARD_BOOT_FLASH_SIZE);
    if (!myboard_flash_boot_map.map_priv_1)
    {
        printk("Failed to ioremap for boot flash!!\n");
        return -EIO;
    }
    
    boot_flash = do_map_probe("cfi_probe", &myboard_flash_boot_map);
    if (boot_flash)
    {
        boot_flash->module = THIS_MODULE;
        boot_flash->erasesize = 0x10000;
    }
    else
    {
        printk("map probe failed for boot flash!!\n");
        return -ENXIO;
    }

    
    /*
     * Oper flash init
     */

    printk(KERN_NOTICE "myboard oper flash: %x at %x\n", BOARD_OPER_FLASH_SIZE, MYBOARD_FLASH_OPER_BASE);
    /* Obtain a virtual address for the physic one given ibn order to perform R/W operations */
    myboard_flash_boot_map.map_priv_1 = (unsigned long)ioremap(MYBOARD_FLASH_OPER_BASE, BOARD_OPER_FLASH_SIZE);
    if (!myboard_flash_oper_map.map_priv_1)
    {
        printk("Failed to ioremap for oper flash!!\n");
        return -EIO;
    }

    oper_flash = do_map_probe("cfi_probe", &myboard_flash_oper_map);
    if (oper_flash)
    {
        oper_flash->module = THIS_MODULE;
        oper_flash->erasesize = 0x10000;
    }
    else
    {
        printk("map probe failed for oper flash!!\n");  
        return -ENXIO;
    }


    /*
     * Create partitions
     */
     
    if(boot_flash && oper_flash)
    {
        add_mtd_partitions(boot_flash,myboard_flash_boot_partitions,sizeof(myboard_flash_boot_partitions)/sizeof(struct mtd_partition));
        add_mtd_partitions(oper_flash,myboard_flash_oper_partitions,sizeof(myboard_flash_oper_partitions)/sizeof(struct mtd_partition));
        return 0; 
    }
    else
    {
        /* Free the obtained virtual addresses */
        iounmap((void *)myboard_flash_boot_map.map_priv_1);
        iounmap((void *)myboard_flash_oper_map.map_priv_1);
        return -ENXIO;
    }
}



/**********************************************/
/*              Module Cleanup                */
/**********************************************/

static void __exit cleanup_myboard_flash(void)
{
    /*
     * Delete partitions
     */
     
    if (boot_flash)
    {
        del_mtd_partitions(boot_flash);
        map_destroy(boot_flash);
    }
    if (oper_flash)
    {
        del_mtd_partitions(oper_flash);
        map_destroy(oper_flash);
    }

    
    /*
     * Free Free the obtained virtual addresses 
     */
     
    if (myboard_flash_boot_map.map_priv_1)
    {
        iounmap((void *)myboard_flash_boot_map.map_priv_1);
        myboard_flash_boot_map.map_priv_1 = 0;
    }
    if (myboard_flash_oper_map.map_priv_1)
    {
        iounmap((void *)myboard_flash_oper_map.map_priv_1);
        myboard_flash_oper_map.map_priv_1 = 0;
    }
}

  

module_init(init_myboard_flash);
module_exit(cleanup_myboard_flash);




-------- Message d'origine--------
De: Josh Boyer [mailto:jwboyer at jdub.homelinux.org]
Date: ven. 01/04/2005 01:34
À: Garcia Jérémie
Cc: linuxppc-dev at ozlabs.org
Objet : Re: How to read/write in flash memories (MTD)?
 
On Thu, 2005-03-31 at 11:59 +0200, Garcia Jérémie wrote:
> L&G,
> Although I'm a newbie in linux kernel development, I'm in charge of adapting a Montavista LSP to fit our hardware. In our platform, we use 2 AMD flash memories (AM29LV) in which one we would like to process read/write operations. So I'm looking for a way to do that. I saw that at compilation time, there is MTD item which seems to be created for that. But I guess activate that will not be enough to reach my objective.

You need to enable MTD with the appropriate chip drivers and either the
MTD character device or the MTD block device (or both).  These will
create /dev/mtdX and /dev/mtdblockX respectively.  If you are using
devfs or sysfs + udev, they should show up in /dev.  Otherwise, you'll
need to use mknod to create them.

> Indeed, we are developping an application (in the user-space) which will initiate operation on the 2 flash memories. So, how can I access them from my application?
> Please help me cause I'm getting lost in the linux sources....

I'm not sure what kind of operations you mean, but the block and char
devices allow read/write operation.  If you are looking for a filesystem
to run on these devices, take a look at JFFS2.  Cramfs or squashfs can
also be used, but they are read-only.

josh




More information about the Linuxppc-dev mailing list