[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [microblaze-uclinux] JFFS2 and MTD
Hi Robert,
Robert Swindells wrote:
> John Williams wrote:
>>I've created a MTD map for the flash devices on the Insight board, and
>>can happily do direct access to and from the flash via /dev/mtdXX and
>>/dev/mtdblockXX.
>
>
> What does your map look like ?
It's attached - pretty straight forward as far as I can tell. I'm using
the CONFIG_FLASH_8MB config option.
Thanks,
John
/****************************************************************************/
/*
* Flash memory access on uClinux mbvanilla Microblaze systems
* Copyright (C) 2003, John Williams <jwilliams@itee.uq.edu.au>
* based upon NETTEL_uc support, which is
* Copyright (C) 2001-2002, David McCullough <davidm@snapgear.com>
*/
/****************************************************************************/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/reboot.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nftl.h>
#include <linux/mtd/map.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/cfi.h>
#include <linux/fs.h>
#include <asm/io.h>
#include <asm/delay.h>
/****************************************************************************/
#define NB_OF(x) (sizeof(x)/sizeof(x[0]))
#define SIZE_128K (128 * 1024)
#define SIZE_1MB (1024 * 1024)
#define SIZE_2MB (2 * 1024 * 1024)
#define SIZE_4MB (4 * 1024 * 1024)
#define SIZE_8MB (8 * 1024 * 1024)
#ifdef CONFIG_MBVANILLA
#define FLASH_BASE 0xff000000
#define BUS_WIDTH 4
#endif
/****************************************************************************/
static __u8 mbvanilla_read8(struct map_info *map, unsigned long ofs)
{
return *(__u8 *)(map->map_priv_1 + ofs);
}
static __u16 mbvanilla_read16(struct map_info *map, unsigned long ofs)
{
return *(__u16 *)(map->map_priv_1 + ofs);
}
static __u32 mbvanilla_read32(struct map_info *map, unsigned long ofs)
{
return *(__u32 *)(map->map_priv_1 + ofs);
}
static void mbvanilla_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
{
memcpy(to, (void *)(map->map_priv_1 + from), len);
}
static void mbvanilla_write8(struct map_info *map, __u8 d, unsigned long adr)
{
*(__u8 *)(map->map_priv_1 + adr) = d;
}
static void mbvanilla_write16(struct map_info *map, __u16 d, unsigned long adr)
{
*(__u16 *)(map->map_priv_1 + adr) = d;
}
static void mbvanilla_write32(struct map_info *map, __u32 d, unsigned long adr)
{
*(__u32 *)(map->map_priv_1 + adr) = d;
}
static void mbvanilla_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
{
memcpy((void *)(map->map_priv_1 + to), from, len);
}
/****************************************************************************/
static struct map_info mbvanilla_flash_map = {
name: "Flash",
read8: mbvanilla_read8,
read16: mbvanilla_read16,
read32: mbvanilla_read32,
copy_from: mbvanilla_copy_from,
write8: mbvanilla_write8,
write16: mbvanilla_write16,
write32: mbvanilla_write32,
copy_to: mbvanilla_copy_to,
};
static struct map_info mbvanilla_ram_map = {
name: "RAM",
read8: mbvanilla_read8,
read16: mbvanilla_read16,
read32: mbvanilla_read32,
copy_from: mbvanilla_copy_from,
write8: mbvanilla_write8,
write16: mbvanilla_write16,
write32: mbvanilla_write32,
copy_to: mbvanilla_copy_to,
};
static struct mtd_info *ram_mtdinfo;
static struct mtd_info *flash_mtdinfo;
/****************************************************************************/
static struct mtd_partition mbvanilla_romfs[] = {
{ name: "Romfs", offset: 0 }
};
/****************************************************************************/
/*
* The layout of our flash, note the order of the names, this
* means we use the same major/minor for the same purpose on all
* layouts (when possible)
*/
static struct mtd_partition mbvanilla_128k[] = {
{ name: "Bootloader", offset: 0x00000000, size: 0x00004000 },
{ name: "Bootargs", offset: 0x00004000, size: 0x00004000 },
{ name: "MAC", offset: 0x00008000, size: 0x00004000 },
{ name: "Config", offset: 0x00010000, size: 0x00010000 },
{ name: "Spare", offset: 0x0000c000, size: 0x00004000 },
{ name: "Flash", offset: 0 }
};
static struct mtd_partition mbvanilla_1mb[] = {
{ name: "Bootloader", offset: 0x00000000, size: 0x00004000 },
{ name: "Bootargs", offset: 0x00004000, size: 0x00002000 },
{ name: "MAC", offset: 0x00006000, size: 0x00002000 },
{ name: "Config", offset: 0x000f0000, size: 0x00010000 },
{ name: "Spare", offset: 0x00008000, size: 0x00008000 },
{ name: "Image", offset: 0x00010000, size: 0x000e0000 },
{ name: "Flash", offset: 0 }
};
static struct mtd_partition mbvanilla_2mb[] = {
{ name: "Bootloader", offset: 0x00000000, size: 0x00004000 },
{ name: "Bootargs", offset: 0x00004000, size: 0x00002000 },
{ name: "MAC", offset: 0x00006000, size: 0x00002000 },
{ name: "Config", offset: 0x00010000, size: 0x00010000 },
{ name: "Spare", offset: 0x00008000, size: 0x00008000 },
{ name: "Image", offset: 0x00020000, size: 0x001e0000 },
{ name: "Flash", offset: 0 }
};
static struct mtd_partition mbvanilla_4mb[] = {
{ name: "Bootloader", offset: 0x00000000, size: 0x00004000 },
{ name: "Bootargs", offset: 0x00004000, size: 0x00002000 },
{ name: "MAC", offset: 0x00006000, size: 0x00002000 },
{ name: "Config", offset: 0x00010000, size: 0x00010000 },
{ name: "Spare", offset: 0x00008000, size: 0x00008000 },
{ name: "Image", offset: 0x00020000, size: 0x001e0000 },
{ name: "Flash", offset: 0x00000000, size: 0x00200000 },
{ name: "Image2", offset: 0x00220000, size: 0x001e0000 },
{ name: "Flash2", offset: 0 }
};
static struct mtd_partition mbvanilla_8mb[] = {
{ name: "Bootloader", offset: 0x00000000, size: 0x00020000 },
{ name: "Bootargs", offset: 0x00020000, size: 0x00020000 },
{ name: "MAC", offset: 0x00040000, size: 0x00020000 },
{ name: "Config", offset: 0x00080000, size: 0x00080000 },
{ name: "Spare", offset: 0x00060000, size: 0x00020000 },
{ name: "Image", offset: 0x00100000, size: 0x00200000 },
{ name: "JFFS2", offset: 0x00300000, size: 0x00500000 },
{ name: "Flash", offset: 0 }
};
/****************************************************************************/
/*
* Find the MTD device with the given name
*/
static struct mtd_info *get_mtd_named(char *name)
{
int i;
struct mtd_info *mtd;
for (i = 0; i < MAX_MTD_DEVICES; i++) {
mtd = get_mtd_device(NULL, i);
if (mtd) {
if (strcmp(mtd->name, name) == 0)
return(mtd);
put_mtd_device(mtd);
}
}
return(NULL);
}
/****************************************************************************/
#ifdef CONFIG_MTD_CFI_INTELEXT
/*
* Set the Intel flash back to read mode as MTD may leave it in command mode
*/
static int mbvanilla_reboot_notifier(
struct notifier_block *nb,
unsigned long val,
void *v)
{
struct cfi_private *cfi = mbvanilla_flash_map.fldrv_priv;
int i;
for (i = 0; cfi && i < cfi->numchips; i++)
cfi_send_gen_cmd(0xff, 0x55, cfi->chips[i].start, &mbvanilla_flash_map,
cfi, cfi->device_type, NULL);
return(NOTIFY_OK);
}
static struct notifier_block mbvanilla_notifier_block = {
mbvanilla_reboot_notifier, NULL, 0
};
#endif
/****************************************************************************/
static int
mbvanilla_point(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char **mtdbuf)
{
struct map_info *map = (struct map_info *) mtd->priv;
*mtdbuf = (u_char *) (map->map_priv_1 + (int)from);
*retlen = len;
return(0);
}
/****************************************************************************/
static int __init
mbvanilla_probe(int ram, unsigned long addr, int size, int buswidth)
{
struct mtd_info *mymtd;
struct map_info *map_ptr;
if (ram)
map_ptr = &mbvanilla_ram_map;
else
map_ptr = &mbvanilla_flash_map;
map_ptr->buswidth = buswidth;
map_ptr->map_priv_2 = addr;
map_ptr->size = size;
printk(KERN_NOTICE "MBVanilla %s probe(0x%lx,%d,%d): %lx at %lx\n",
ram ? "ram" : "flash",
addr, size, buswidth, map_ptr->size, map_ptr->map_priv_2);
map_ptr->map_priv_1 = (unsigned long)
ioremap_nocache(map_ptr->map_priv_2, map_ptr->size);
if (!map_ptr->map_priv_1) {
printk("Failed to ioremap_nocache\n");
return -EIO;
}
if (!ram) {
mymtd = do_map_probe("cfi_probe", map_ptr);
if (!mymtd)
mymtd = do_map_probe("jedec_probe", map_ptr);
} else
mymtd = do_map_probe("map_ram", map_ptr);
if (!mymtd) {
iounmap((void *)map_ptr->map_priv_1);
return -ENXIO;
}
mymtd->module = THIS_MODULE;
mymtd->point = mbvanilla_point;
mymtd->priv = map_ptr;
if (ram) {
ram_mtdinfo = mymtd;
add_mtd_partitions(mymtd, mbvanilla_romfs, NB_OF(mbvanilla_romfs));
return(0);
}
flash_mtdinfo = mymtd;
switch (size) {
case SIZE_128K:
add_mtd_partitions(mymtd, mbvanilla_128k, NB_OF(mbvanilla_128k));
break;
case SIZE_1MB:
add_mtd_partitions(mymtd, mbvanilla_1mb, NB_OF(mbvanilla_1mb));
break;
case SIZE_2MB:
add_mtd_partitions(mymtd, mbvanilla_2mb, NB_OF(mbvanilla_2mb));
break;
case SIZE_4MB:
add_mtd_partitions(mymtd, mbvanilla_4mb, NB_OF(mbvanilla_4mb));
break;
case SIZE_8MB:
add_mtd_partitions(mymtd, mbvanilla_8mb, NB_OF(mbvanilla_8mb));
break;
}
return 0;
}
/****************************************************************************/
int __init mbvanilla_mtd_init(void)
{
int rc = -1;
struct mtd_info *mtd;
extern char _ebss;
extern char _root_fs_image_start, _root_fs_image_end;
/*
* I hate this ifdef stuff, but our HW doesn't always have
* the same chipsize as the map that we use
*/
#if defined(CONFIG_FLASH8MB) || defined(CONFIG_FLASHAUTO)
if (rc != 0)
rc = mbvanilla_probe(0, FLASH_BASE, SIZE_8MB, BUS_WIDTH);
#endif
#if defined(CONFIG_FLASH4MB) || defined(CONFIG_FLASHAUTO)
if (rc != 0)
rc = mbvanilla_probe(0, FLASH_BASE, SIZE_4MB, BUS_WIDTH);
#endif
#if defined(CONFIG_FLASH2MB) || defined(CONFIG_FLASHAUTO)
if (rc != 0)
rc = mbvanilla_probe(0, FLASH_BASE, SIZE_2MB, BUS_WIDTH);
#endif
#if defined(CONFIG_FLASH1MB) || defined(CONFIG_FLASHAUTO)
if (rc != 0)
rc = mbvanilla_probe(0, FLASH_BASE, SIZE_1MB, BUS_WIDTH);
#endif
#if defined(CONFIG_FLASH128K) || defined(CONFIG_FLASHAUTO)
if (rc != 0)
rc = mbvanilla_probe(0, FLASH_BASE, SIZE_128K, BUS_WIDTH);
#endif
#ifdef CONFIG_MBVANILLA
/*
* Map in the filesystem from RAM last so that, if the filesystem
* is not in RAM for some reason we do not change the minor/major
* for the flash devices
*/
#ifndef CONFIG_SEARCH_ROMFS
if (0 != mbvanilla_probe(1, (unsigned long) &_ebss,
PAGE_ALIGN(* (unsigned long *)((&_ebss) + 8)),4))
printk("Failed to probe RAM filesystem\n");
#else
{
unsigned long start_area;
unsigned char *sp, *ep;
size_t len;
printk("Probing for ROMFS...\n");
start_area = (unsigned long) &_ebss;
if (strncmp((char *) start_area, "-rom1fs-", 8) != 0) {
mtd = get_mtd_named("Image");
if (mtd && mtd->point) {
if ((*mtd->point)(mtd, 0, mtd->size, &len, &sp) == 0) {
ep = sp + len;
while (sp < ep && strncmp(sp, "-rom1fs-", 8) != 0)
sp++;
if (sp < ep)
start_area = (unsigned long) sp;
}
}
if (mtd)
put_mtd_device(mtd);
}
if (0 != mbvanilla_probe(1, start_area,
PAGE_ALIGN(* (unsigned long *)(start_area + 8)), 4))
printk("Failed to probe RAM filesystem\n");
}
#endif
mtd = get_mtd_named("Romfs");
if (mtd) {
ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, mtd->index);
put_mtd_device(mtd);
}
#endif
return(rc);
}
/****************************************************************************/
static void __exit mbvanilla_mtd_cleanup(void)
{
if (flash_mtdinfo) {
del_mtd_partitions(flash_mtdinfo);
map_destroy(flash_mtdinfo);
flash_mtdinfo = NULL;
}
if (ram_mtdinfo) {
del_mtd_partitions(ram_mtdinfo);
map_destroy(ram_mtdinfo);
ram_mtdinfo = NULL;
}
if (mbvanilla_ram_map.map_priv_1) {
iounmap((void *)mbvanilla_ram_map.map_priv_1);
mbvanilla_ram_map.map_priv_1 = 0;
}
if (mbvanilla_flash_map.map_priv_1) {
iounmap((void *)mbvanilla_flash_map.map_priv_1);
mbvanilla_flash_map.map_priv_1 = 0;
}
}
/****************************************************************************/
module_init(mbvanilla_mtd_init);
module_exit(mbvanilla_mtd_cleanup);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("John Williams <jwilliams@itee.uq.edu.au>");
MODULE_DESCRIPTION("Microblaze/MBVanilla FLASH support for uClinux");
/****************************************************************************/