345 lines
8.7 KiB
C
345 lines
8.7 KiB
C
/*
|
|
* A simple flash mapping code for BCM963xx board flash memory
|
|
* It is simple because it only treats all the flash memory as ROM
|
|
* It is used with chips/map_rom.c
|
|
*
|
|
* Song Wang (songw@broadcom.com)
|
|
*/
|
|
|
|
#include <linux/module.h>
|
|
#include <linux/types.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/init.h>
|
|
#include <asm/io.h>
|
|
#include <linux/mtd/mtd.h>
|
|
#include <linux/mtd/map.h>
|
|
//#include <linux/config.h>
|
|
|
|
#include <board.h>
|
|
#include <bcmTag.h>
|
|
#include <bcm_map_part.h>
|
|
#define VERSION "1.0"
|
|
|
|
extern PFILE_TAG kerSysImageTagGet(void);
|
|
|
|
#if !defined(CONFIG_BRCM_IKOS)
|
|
extern int kerSysEraseFlash(unsigned long eraseaddr,unsigned long len);
|
|
extern int kerSysWriteToFlash(unsigned long toaddr,void * fromaddr, unsigned long len);
|
|
#endif
|
|
|
|
#define BCM_MTD_VERSION "2.0" /* NOR FLASH ONLY */
|
|
|
|
const char * null_mtd_c = "NULLMTD";
|
|
|
|
/*
|
|
* MTD Driver Entry Points using kerSys interface to flash_api
|
|
*
|
|
* Assumption:
|
|
* - Single region with all sectors of the same size per MTD device registered.
|
|
* - BankSize = 2
|
|
*
|
|
* Runtime spcification of device size, offset using Flash Partition Info.
|
|
*/
|
|
|
|
static int bcm63xx_erase_invalid(struct mtd_info *mtd, struct erase_info *instr)
|
|
{
|
|
const char * mtdname_p = (char*)null_mtd_c;
|
|
if ( mtd ) mtdname_p = mtd->name;
|
|
printk("ERROR: bcm63xx_erase_invalid( mtd[%s])\n", mtdname_p );
|
|
|
|
/* Proceed as if done */
|
|
instr->state = MTD_ERASE_DONE;
|
|
mtd_erase_callback( instr );
|
|
|
|
return (0);
|
|
}
|
|
|
|
static int bcm63xx_erase(struct mtd_info *mtd, struct erase_info *instr)
|
|
{
|
|
unsigned long flash_base;
|
|
if ( mtd == (struct mtd_info *)NULL )
|
|
{
|
|
printk("ERROR: bcm63xx_erase( mtd[%s])\n", null_mtd_c);
|
|
return (-EINVAL);
|
|
}
|
|
|
|
if ( instr->addr + instr->len > mtd->size )
|
|
{
|
|
printk("ERROR: bcm63xx_erase( mtd[%s]) invalid region\n", mtd->name);
|
|
return (-EINVAL);
|
|
}
|
|
|
|
flash_base = (unsigned long)mtd->priv;
|
|
|
|
#if !defined(CONFIG_BRCM_IKOS)
|
|
if ( kerSysEraseFlash( flash_base + instr->addr, instr->len) )
|
|
return (-EINVAL);
|
|
#endif
|
|
|
|
instr->state = MTD_ERASE_DONE;
|
|
mtd_erase_callback( instr );
|
|
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
static int bcm63xx_point_invalid(struct mtd_info *mtd, loff_t from,
|
|
size_t len, size_t *retlen, u_char **mtdbuf)
|
|
{
|
|
return (-EINVAL);
|
|
}
|
|
|
|
static void bcm63xx_unpoint_invalid(struct mtd_info *mtd, u_char * addr,
|
|
loff_t from, size_t len)
|
|
{
|
|
}
|
|
|
|
*/
|
|
static int bcm63xx_read(struct mtd_info *mtd, loff_t from, size_t len,
|
|
size_t *retlen, u_char *buf)
|
|
{
|
|
unsigned long flash_base;
|
|
*retlen = 0;
|
|
if ( mtd == (struct mtd_info *)NULL )
|
|
{
|
|
printk("ERROR: bcm63xx_read( mtd[%s])\n", null_mtd_c);
|
|
return (-EINVAL);
|
|
}
|
|
flash_base = (unsigned long)mtd->priv;
|
|
|
|
*retlen = kerSysReadFromFlash(buf, flash_base + from, len);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int bcm63xx_write_invalid(struct mtd_info *mtd, loff_t to, size_t len,
|
|
size_t *retlen, const u_char *buf)
|
|
{
|
|
const char * mtdname_p = (char*)null_mtd_c;
|
|
*retlen = 0;
|
|
if ( mtd ) mtdname_p = mtd->name;
|
|
printk("ERROR: bcm63xx_write_invalid( mtd[%s])\n", mtdname_p );
|
|
|
|
return (-EINVAL);
|
|
}
|
|
|
|
static int bcm63xx_write(struct mtd_info *mtd, loff_t to, size_t len,
|
|
size_t *retlen, const u_char *buf)
|
|
{
|
|
unsigned long flash_base;
|
|
#if !defined(CONFIG_BRCM_IKOS)
|
|
int bytesRemaining = 0;
|
|
#endif
|
|
|
|
*retlen = 0;
|
|
if ( mtd == (struct mtd_info *)NULL )
|
|
{
|
|
printk("ERROR: bcm63xx_write( mtd[%s])\n", null_mtd_c);
|
|
return (-EINVAL);
|
|
}
|
|
flash_base = (unsigned long)mtd->priv;
|
|
|
|
#if !defined(CONFIG_BRCM_IKOS)
|
|
bytesRemaining = kerSysWriteToFlash(flash_base+to, (char*)buf, len);
|
|
*retlen = (len - bytesRemaining);
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
static void bcm63xx_noop(struct mtd_info *mtd)
|
|
{
|
|
/* NO OPERATION */
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
* List of Broadcom MTD Devices per supported Flash File Systems
|
|
*
|
|
* - Non WRITEABLE MTD device for the Root FileSystem/kernel
|
|
* [e.g. the RootFS MTD may host SquashFS]
|
|
* - WRITEABLE MTD device for an Auxillary FileSystem, if configured
|
|
* [e.g. the AuxFS MTD may host JFFS2]
|
|
*---------------------------------------------------------------------------*/
|
|
|
|
static struct mtd_info mtdRootFS =
|
|
{
|
|
.name = "BCM63XX RootFS",
|
|
.index = -1, /* not registered */
|
|
.type = MTD_NORFLASH,
|
|
.flags = 0,/* No capability: i.e. CLEAR/SET BITS, ERASEABLE */
|
|
.size = 0,
|
|
.erasesize = 0, /* NO ERASE */
|
|
.writesize = 1,
|
|
.numeraseregions= 0,
|
|
.eraseregions = (struct mtd_erase_region_info*) NULL,
|
|
//.bank_size = 2,
|
|
.read = bcm63xx_read,
|
|
.erase = bcm63xx_erase_invalid, /* READONLY */
|
|
.write = bcm63xx_write_invalid, /* READONLY */
|
|
//.point = bcm63xx_point_invalid, /* No XIP */
|
|
//.unpoint = bcm63xx_unpoint_invalid, /* No XIP */
|
|
.sync = bcm63xx_noop,
|
|
// NAND Flash Devices not supported: ecc, oob, kvec read/write
|
|
.priv = (void*) NULL,
|
|
.owner = THIS_MODULE
|
|
};
|
|
|
|
#ifdef CONFIG_AUXFS_JFFS2
|
|
struct mtd_erase_region_info merAuxFS =
|
|
{
|
|
.offset = 0,
|
|
.erasesize = 0,
|
|
.numblocks = 0
|
|
};
|
|
|
|
static struct mtd_info mtdAuxFS =
|
|
{
|
|
.name = "BCM63XX AuxFS",
|
|
.index = -1, /* not registered */
|
|
.type = MTD_NORFLASH,
|
|
.flags = MTD_CAP_NORFLASH, /* MTD_CLEAR_BITS | MTD_ERASEABLE */
|
|
/* No SET_BITS, WRITEB_WRITEABLE, MTD_OOB */
|
|
.numeraseregions= 1,
|
|
.eraseregions = (struct mtd_erase_region_info*) &merAuxFS,
|
|
.writesize = 1,
|
|
//.bank_size = 2,
|
|
.read = bcm63xx_read,
|
|
.erase = bcm63xx_erase,
|
|
.write = bcm63xx_write,
|
|
// .point = bcm63xx_point_invalid, /* No XIP */
|
|
// .unpoint = bcm63xx_unpoint_invalid, /* No XIP */
|
|
.sync = bcm63xx_noop,
|
|
// NAND Flash Devices not supported: ecc, oob, kvec read/write
|
|
.priv = (void*) NULL,
|
|
.owner = THIS_MODULE
|
|
};
|
|
#endif
|
|
|
|
static int __init init_brcm_physmap(void)
|
|
{
|
|
unsigned int rootfs_addr, kernel_addr;
|
|
PFILE_TAG pTag = (PFILE_TAG)NULL;
|
|
|
|
#ifdef CONFIG_AUXFS_JFFS2
|
|
FLASH_PARTITION_INFO fPartAuxFS; /* Runtime partitioning info */
|
|
#endif
|
|
|
|
printk("bcm963xx_mtd driver v%s\n", BCM_MTD_VERSION);
|
|
|
|
/*
|
|
* Data fill the runtime configuration of MTD RootFS Flash Device
|
|
*/
|
|
if (! (pTag = kerSysImageTagGet()) )
|
|
{
|
|
printk("Failed to read image tag from flash\n");
|
|
return -EIO;
|
|
}
|
|
|
|
rootfs_addr = (unsigned int)
|
|
simple_strtoul(pTag->rootfsAddress, NULL, 10)
|
|
+ BOOT_OFFSET;
|
|
kernel_addr = (unsigned int)
|
|
simple_strtoul(pTag->kernelAddress, NULL, 10)
|
|
+ BOOT_OFFSET;
|
|
if ((mtdRootFS.size = (kernel_addr - rootfs_addr)) <= 0)
|
|
{
|
|
printk("Invalid RootFs size\n");
|
|
return -EIO;
|
|
}
|
|
|
|
/*
|
|
* CAUTION:
|
|
* rootfs_addr is NOT ALIGNED WITH a sector boundary.
|
|
* As, RootFS MTD is not writeable and not explicit erase capability
|
|
* this is not an issue.
|
|
* Support for writeable RootFS mtd would need to take into account
|
|
* the offset of rootfs_addr from the sector base.
|
|
*/
|
|
mtdRootFS.priv = (void*)rootfs_addr;
|
|
|
|
if ( add_mtd_device( &mtdRootFS ) ) /* Register Device RootFS */
|
|
{
|
|
printk("Failed to register device mtd[%s]\n", mtdRootFS.name);
|
|
return -EIO;
|
|
}
|
|
|
|
printk("Registered device mtd[%s] dev[%d] Flash[0x%08x,%llu]\n",
|
|
mtdRootFS.name, mtdRootFS.index,
|
|
(int)mtdRootFS.priv, mtdRootFS.size);
|
|
|
|
|
|
#ifdef CONFIG_AUXFS_JFFS2
|
|
/*
|
|
* Data fill the runtime configuration of MTD AuxFS Flash Device
|
|
*/
|
|
/* Read the flash memory partition map. */
|
|
kerSysFlashPartInfoGet(& fPartAuxFS );
|
|
|
|
/*
|
|
* Assuming a single eraseregion with all sectors of the same size!!!
|
|
*/
|
|
if ( fPartAuxFS.sect_size != 0 ) /* Check assumption */
|
|
{
|
|
mtdAuxFS.priv = (void*)fPartAuxFS.mem_base;
|
|
mtdAuxFS.size = fPartAuxFS.mem_length;
|
|
|
|
mtdAuxFS.erasesize = fPartAuxFS.sect_size;
|
|
|
|
mtdAuxFS.numeraseregions = 1;
|
|
mtdAuxFS.eraseregions->offset = 0;
|
|
mtdAuxFS.eraseregions->erasesize = fPartAuxFS.sect_size;
|
|
mtdAuxFS.eraseregions->numblocks = fPartAuxFS.number_blk;
|
|
|
|
if ( add_mtd_device( & mtdAuxFS ) ) /*Register Device AuxFS */
|
|
{
|
|
printk("Failed to register device mtd[%s]\n",
|
|
mtdAuxFS.name);
|
|
return -EIO;
|
|
}
|
|
|
|
printk("Registered device mtd[%s] dev[%d] Flash[0x%08x,%llu]\n",
|
|
mtdAuxFS.name, mtdAuxFS.index,
|
|
(int)mtdAuxFS.priv, mtdAuxFS.size);
|
|
|
|
}
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
static void __exit cleanup_brcm_physmap(void)
|
|
{
|
|
if (mtdRootFS.index >= 0)
|
|
{
|
|
mtdRootFS.index = -1;
|
|
|
|
del_mtd_device( &mtdRootFS );
|
|
|
|
mtdRootFS.size = 0;
|
|
mtdRootFS.priv = (void*)NULL;
|
|
}
|
|
|
|
#ifdef CONFIG_AUXFS_JFFS2
|
|
if (mtdAuxFS.index >= 0)
|
|
{
|
|
mtdAuxFS.index = -1;
|
|
|
|
del_mtd_device( &mtdAuxFS );
|
|
|
|
mtdAuxFS.size = 0;
|
|
mtdAuxFS.priv = (void*)NULL;
|
|
mtdAuxFS.erasesize = 0;
|
|
mtdAuxFS.numeraseregions = 0;
|
|
mtdAuxFS.eraseregions->offset = 0;
|
|
mtdAuxFS.eraseregions->erasesize = 0;
|
|
mtdAuxFS.eraseregions->numblocks = 0;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
module_init(init_brcm_physmap);
|
|
module_exit(cleanup_brcm_physmap);
|
|
|
|
|
|
MODULE_LICENSE("GPL");
|
|
MODULE_AUTHOR("Song Wang songw@broadcom.com");
|
|
MODULE_DESCRIPTION("Configurable MTD Driver for Broadcom Flash File System");
|