mpc8270 and 64bit flash geometry
Hello,
We have designed a board using the mpc8270 and have problm accessing the fLASH using linux-2.6.15.1
We have placed the FLASH on the 60x bus. Here is the geometry:
-FLASH Part number: M29DW640D70ZA1
-There are 2 Flash Memory Banks of 32MB each. So each bank has 4 chips that are banked to form a 64b wide bus.
-Write to FLASH: as we have a single WE signal per bank, the write operation is done 64bits at a time. That is the CPU has to generate a 64bit write. It can't write in 8,16,32bit mode.
With that in mind I have selected an interleave of 4 and bankwidth of 8.
We now know this single WE poses problem. From reading the archive it seems there is a work around by defining a write routine in the map driver that uses the 64b load/store floating point instrcutions. So I have done that, but I still can't do an "eraseall" (it will panic the system).
Besides the specific write routine, anything else I need to do? Or the MTD code will simply not work with this kind of geometry?
Looking at the code, I have one question: SHould ./mtd/chips/cfi_probe.c:cfi_probe_chip() be called for _every_ flash chip? It seems to be called only once per bank.
Thanks
Best regards,
_______________________________________
jean-francois simon - themis computer
5, rue irene joliot curie
38330 eybens - france
+33 (0)870 448 638
+33 (0)4 76 14 77 85 - [email protected]
___________________________________________________________________________ Yahoo! Mail réinvente le mail ! Découvrez le nouveau Yahoo! Mail et son interface révolutionnaire.
http://fr.mail.yahoo.com
Quoted 6 lines · jean-francois simon
We now know this single WE poses problem. From reading the archive it seems there is a work around by defining a write routine in the map driver that uses the 64b load/store floating point instrcutions.
So I have done that, but I still can't do an "eraseall" (it will panic the system).
Show the panic. If you're using floating point registers in the kernel, you need to do that carefully and properly.
Quoted 2 lines
Besides the specific write routine, anything else I need to do? Or the MTD code will simply not work with this kind of geometry?
It ought to work.
Quoted 3 lines
Looking at the code, I have one question: SHould ./mtd/chips/cfi_probe.c:cfi_probe_chip() be called for _every_ flash chip? It seems to be called only once per bank.
Er, I think we just assume that all the chips are identical.
Signature · 1 line
dwmw2
Hi again,
Quoted 3 lines
Show the panic. If you're using floating point registers in the kernel, you need to do that carefully and properly.
I have enclosed my map driver below and the "floating point" write routine. I think it works, or I will not go very far. Strangely I can no longer trigger a panic now. Instead I get input/output errors on "eraseall", although it does its job, as I can write to a device and then write to it:
bash-3.00# cat /etc/hosts
127.0.0.1 localhost
bash-3.00# cat /etc/hosts >/dev/mtd1
bash-3.00# dd if=/dev/mtd1 of=/tmp/ppp
2048+0 records in
2048+0 records out
bash-3.00# od -x /tmp/ppp
0000000 3132 372e 302e 302e 3109 096c 6f63 616c
0000020 686f 7374 0aff ffff ffff ffff ffff ffff
0000040 ffff ffff ffff ffff ffff ffff ffff ffff
*
4000000
bash-3.00
ash-3.00# eraseall /dev/mtd1
Erasing 256 Kibyte @ 0 -- 0 % complete.
eraseall: /dev/mtd1: MTD Erase failure: Input/output error Erasing 256 Kibyte @ 40000 -- 25 % complete.
eraseall: /dev/mtd1: MTD Erase failure: Input/output error Erasing 256 Kibyte @ 80000 -- 50 % complete.
eraseall: /dev/mtd1: MTD Erase failure: Input/output error Erasing 256 Kibyte @ c0000 -- 75 % complete.
eraseall: /dev/mtd1: MTD Erase failure: Input/output error Erased 1024 Kibyte @ 0 -- 100% complete. bash-3.00#
bash-3.00# dd if=/dev/mtd1 of=/tmp/ppp
2048+0 records in
2048+0 records out
bash-3.00# od -x /tmp/ppp
0000000 ffff ffff ffff ffff ffff ffff ffff ffff
*
4000000
Also I have joined the boot messages, and the MTD options from .config.
I have been working on this for several days. If there is anything obvious, plse let me know. Thanks a lot,
-jfs
My boot messages:
Linux version 2.6.15 (bmc@Linux188) (gcc version 4.0.0 (DENX ELDK 4.0 4.0.0)) #433 Fri May 26 11:26:14 PDT 2006
Themis Commputer BMC - (mpc8270) port
Built 1 zonelists
Kernel command line: root=/dev/nfs rw nfsroot=192.168.44.8:/home/bmc/tools/eldk4.0/ppc_6xx ip=192.168.44.27:192.168.44.8:192.168.44.254:255.255.255.0:bmc8:eth1:off panic=1 PID hash table entries: 2048 (order: 11, 32768 bytes)
Warning: real time clock seems stuck!
Dentry cache hash table entries: 65536 (order: 6, 262144 bytes)
Inode-cache hash table entries: 32768 (order: 5, 131072 bytes)
Memory: 257280k available (1548k kernel code, 628k data, 92k init, 0k highmem)
Mount-cache hash table entries: 512
NET: Registered protocol family 16
fs/char_dev.c register_chrdev major=10,misc
fs/char_dev.c register_chrdev major=1,mem
JFFS2 version 2.2. (NAND) (C) 2001-2003 Red Hat, Inc.
JFFS2: default compression mode: priority
io scheduler noop registered
io scheduler anticipatory registered
io scheduler deadline registered
io scheduler cfq registered
Generic RTC Driver v1.07
Serial: CPM driver $Revision: 0.01 $
ttyCPM0 at MMIO 0xf0011a80 (irq = 4) is a CPM UART
ttyCPM1 at MMIO 0xf0011a90 (irq = 5) is a CPM UART
ttyCPM2 at MMIO 0xf0011a00 (irq = 40) is a CPM UART RAMDISK driver initialized: 16 RAM disks of 4096K size 1024 blocksize
fs/char_dev.c register_chrdev major=90,mtd
$Id: ftl.c,v 1.59 2005/11/29 14:48:31 gleixner Exp $ bmc82xx.c init_bmc_mtd flash_addr=fc000000, flash_size=4000000init_bmc_mtd: chip probing count 0
Number of erase regions: 3
Primary Vendor Command Set: 0002 (AMD/Fujitsu Standard) Primary Algorithm Table at 0040
Alternative Vendor Command Set: 0000 (None)
No Alternate Algorithm Table
Vcc Minimum: 2.7 V Vcc Maximum: 3.6 V Vpp Minimum: 11.5 V Vpp Maximum: 12.5 V Typical byte/word write timeout: 16 µs Maximum byte/word write timeout: 256 µs
Full buffer write not supported
Typical block erase timeout: 1024 ms
Maximum block erase timeout: 8192 ms
Chip erase not supported
Device size: 0x800000 bytes (8 MiB)
Flash Device Interface description: 0x0002
- supports x8 and x16 via BYTE# with asynchronous interface
Max. bytes in buffer write: 0x40
Number of Erase Block Regions: 3
Erase Region #0: BlockSize 0x2000 bytes, 8 blocks
Erase Region #1: BlockSize 0x10000 bytes, 126 blocks
Erase Region #2: BlockSize 0x2000 bytes, 8 blocks
BMC82xx-0: Found 4 x16 devices at 0x0 in 64-bit bank
Amd/Fujitsu Extended Query Table at 0x0040
BMC82xx-0: CFI does not contain boot bank location. Assuming top. number of CFI chips: 1cfi_cmdset_0002: Disabling erase-suspend-program due to code brokenness.init_bmc_mtd: bank1, name:BMC82xx-0, size:33554432bytes
BMC flash0: Using Static image partition definition
Creating 3 MTD partitions on "BMC82xx-0":
0x00000000-0x00020000 : "bmc1"
mtd: Giving out device 0 to bmc1rfd_ftl: no RFD magic found in 'bmc1'ftl_cs: FTL header not found.
0x00100000-0x00200000 : "bmc2"
mtd: Giving out device 1 to bmc2rfd_ftl: no RFD magic found in 'bmc2'ftl_cs: FTL header not found.
0x00000000-0x02000000 : "bmc3"
mtd: Giving out device 2 to bmc3rfd_ftl: no RFD magic found in 'bmc3'ftl_cs: FTL header not found.
(snip)
................
MTD related OPTIONS:
#
# Memory Technology Devices (MTD)
#CONFIG_MTD=yCONFIG_MTD_DEBUG=yCONFIG_MTD_DEBUG_VERBOSE=3CONFIG_MTD_CONCAT=yCONFIG_MTD_PARTITIONS=y
# CONFIG_MTD_REDBOOT_PARTS is not setCONFIG_MTD_CMDLINE_PARTS=y
#
# User Modules And Translation Layers
#CONFIG_MTD_CHAR=yCONFIG_MTD_BLOCK=yCONFIG_FTL=y
# CONFIG_NFTL is not set
# CONFIG_INFTL is not setCONFIG_RFD_FTL=y
#
# RAM/ROM/Flash chip drivers
#CONFIG_MTD_CFI=yCONFIG_MTD_JEDECPROBE=yCONFIG_MTD_GEN_PROBE=yCONFIG_MTD_CFI_ADV_OPTIONS=yCONFIG_MTD_CFI_NOSWAP=y
# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
# CONFIG_MTD_CFI_LE_BYTE_SWAP is not setCONFIG_MTD_CFI_GEOMETRY=y
# CONFIG_MTD_MAP_BANK_WIDTH_1 is not set
# CONFIG_MTD_MAP_BANK_WIDTH_2 is not set
# CONFIG_MTD_MAP_BANK_WIDTH_4 is not setCONFIG_MTD_MAP_BANK_WIDTH_8=y
# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
# CONFIG_MTD_CFI_I1 is not set
# CONFIG_MTD_CFI_I2 is not setCONFIG_MTD_CFI_I4=y
# CONFIG_MTD_CFI_I8 is not set
# CONFIG_MTD_OTP is not set
# CONFIG_MTD_CFI_INTELEXT is not setCONFIG_MTD_CFI_AMDSTD=yCONFIG_MTD_CFI_AMDSTD_RETRY=5
# CONFIG_MTD_CFI_STAA is not setCONFIG_MTD_CFI_UTIL=y
# CONFIG_MTD_RAM is not set
# CONFIG_MTD_ROM is not set
# CONFIG_MTD_ABSENT is not set
#
# Mapping drivers for chip access
#CONFIG_MTD_COMPLEX_MAPPINGS=y
# CONFIG_MTD_PHYSMAP is not set
# CONFIG_MTD_SBC8240 is not set
# CONFIG_MTD_PM82X is not set
CONFIG_MTD_BMC82xx=y
# CONFIG_MTD_PLATRAM is not set
#
# Self-contained MTD device drivers
#
# CONFIG_MTD_SLRAM is not set
# CONFIG_MTD_PHRAM is not set
# CONFIG_MTD_MTDRAM is not set
# CONFIG_MTD_BLKMTD is not set
# CONFIG_MTD_BLOCK2MTD is not set
#
# Disk-On-Chip Device Drivers
#
# CONFIG_MTD_DOC2000 is not set
# CONFIG_MTD_DOC2001 is not set
# CONFIG_MTD_DOC2001PLUS is not set
#
# NAND Flash Device Drivers
#
# CONFIG_MTD_NAND is not set
#
# OneNAND Flash Device Drivers
#
# CONFIG_MTD_ONENAND is not set
........................
[bmc@Linux188 maps]$
[bmc@Linux188 maps]$ cat bmc82xx.c
/*
* Handle mapping of the flash memory access routines
* on THEMIS Computer BMC82xx based devices. *
* Based on tqm82xx.c map driver
*
*/
/*
* According to BMC hardware manual, it has
* following flash memory organisations:
* | capacity | | chip type | | bank0 | | bank1 |
* 64MiB M29DW641D 32MiB 32MiB
* Thus, we choose CONFIG_MTD_CFI_I4 & CONFIG_MTD_CFI_B8 at
* kernel configuration.
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
#include <linux/mtd/partitions.h>
#include <asm/io.h>
#define FLASH_BANK_MAX 1
// trivial struct to describe partition information struct mtd_part_def
{
int nums;
unsigned char *type;
struct mtd_partition* mtd_part;
};//static struct mtd_info *mymtd;
static struct mtd_info* mtd_banks[FLASH_BANK_MAX]; //jfas static struct map_info* map_banks[FLASH_BANK_MAX]; static struct map_info* map_banks[FLASH_BANK_MAX]; static struct mtd_part_def part_banks[FLASH_BANK_MAX]; static unsigned long num_banks;
static void __iomem *start_scan_addr;
#ifdef CONFIG_MTD_PARTITIONS
/* Currently, BMC82xx has upto 64 MiB flash */
/* partition definition for first flash bank
*/
static struct mtd_partition bmc82xx_partitions[] = {
{
.name = "bmc1",
.offset = 0x00000000,
.size = 0x00020000, /* 128KB */
.mask_flags = MTD_WRITEABLE, /* force read-only */
},
{
.name = "bmc2",
.offset = 0x00100000,
.size = 0x00100000,
},
{
.name = "bmc3",
.offset = 0x00000000,
.size = 0x02000000,
}
};#if 0
/* partition definition for second flash bank */
static struct mtd_partition bmc82xx_fs_partitions[] = {
/* overlapping all flash 1 (32MB) */
{
.name = "bmc4",
.offset = 0x00000000,
.size = 0x02000000,
}
};#endif
#endif
static map_word bmc82xx_read64(struct map_info *map, unsigned long ofs)
{
map_word val;// printk("bmc82xx_read64 %x\n", map->virt+ofs);
val.x[0] = *((volatile __u32 *)(map->virt+ ofs));
val.x[1] = *(((volatile __u32 *)(map->virt + ofs)) + 1);
return val;
}static void bmc82xx_write64 (struct map_info *map, map_word map_d,
unsigned long adr)
{
ulong flags;
volatile ulong msr;
ulong saved_msr;
volatile long saved_fr[2];
uint32_t addr = (uint32_t)map->virt + adr; //jfas!!
uint32_t* data;#define ALIGNUP(x,y) (((x) + ((y) - 1)) & ~((y) - 1))
data = kmalloc(0x100, GFP_KERNEL);
if(data == NULL) {
printk("bmc82xx_write64: kmalloc failed\n");
return;
}
data = ALIGNUP( (uint32_t)data, 0x8);
data[0] = (map_d.x[0]);
data[1] = + map_d.x[1];
local_irq_save (flags);
__asm__ __volatile__ ("mfmsr %0" : "=r" (msr):);
saved_msr = msr;
msr |= MSR_FP;
msr &= ~(MSR_FE0 | MSR_FE1);
__asm__ __volatile__ (
"mtmsr %0\n"
"isync\n"
:
: "r" (msr));
__asm__ __volatile__ (
"stfd 1, 0(%2)\n"
"lfd 1, 0(%0)\n"
"stfd 1, 0(%1)\n"
"lfd 1, 0(%2)\n"
:
: "r" (data), "r" (addr), "b" (saved_fr)
);
__asm__ __volatile__ (
"mtmsr %0\n"
"isync\n"
:
: "r" (saved_msr));
kfree(data);
local_irq_restore (flags);
}static void bmc82xx_copy_to(struct map_info *map,
unsigned long to, const void *from, ssize_t len)
{
map_word val;
uint32_t *ptr = (uint32_t*)from;printk("bmc82xx_copy_to: \n");
if (len % 8){
printk("bmc82xx_copy_to: Error length not
multiple of 8\n");
return;
}
while (len){
val.x[0] = *((volatile __u32 *)(*ptr++));
val.x[1] = *((volatile __u32 *)(*ptr++));
bmc82xx_write64(map, val, to);
len -= 8;
to += 8;
}}
int __init init_bmc_mtd(void)
{
int idx = 0, ret = 0;
unsigned long flash_addr, flash_size, mtd_size = 0;
/* pointer to BMC82xx board info data */
bd_t *bd = (bd_t *)__res;
flash_addr = bd->bi_flashstart;
flash_size = bd->bi_flashsize;#if 1 /* debug -> bmc */
printk(KERN_INFO "bmc82xx.c init_bmc_mtd flash_addr=%lx,
flash_size=%lx\n", flash_addr, flash_size);
#endif
//request maximum flash size address space
start_scan_addr = ioremap(flash_addr, flash_size);
if (!start_scan_addr) {
printk(KERN_WARNING "%s:Failed to ioremap
address:0x%x\n", __FUNCTION__, (unsigned int)flash_addr);
return -EIO;
}
for (idx = 0 ; idx < FLASH_BANK_MAX ; idx++) {
if(mtd_size >= flash_size)
break;
printk(KERN_INFO "%s: chip probing count %d\n", __FUNCTION__, idx);
map_banks[idx] = (struct map_info
*)kmalloc(sizeof(struct map_info), GFP_KERNEL);
if(map_banks[idx] == NULL) {
ret = -ENOMEM;
/* FIXME: What if some MTD devices were
probed already? */
goto error_mem;
}
memset((void *)map_banks[idx], 0, sizeof(struct
map_info));
map_banks[idx]->name = (char *)kmalloc(16, GFP_KERNEL);
if (!map_banks[idx]->name) {
ret = -ENOMEM;
/* FIXME: What if some MTD devices were
probed already? */
goto error_mem;
}
sprintf(map_banks[idx]->name, "BMC82xx-%d", idx);
map_banks[idx]->size = flash_size / 2;
map_banks[idx]->bankwidth = 8;
simple_map_init(map_banks[idx]);//BMC - jfas: We patch the write methods from simple_map_init() to a new one to make up for the fact that the FLASH is 64b wide, w/ all 4 FLASH chips sharing the same WE signal. It seems only assembly can generate a true 64b wide access.
map_banks[idx]->write = bmc82xx_write64;
map_banks[idx]->read = bmc82xx_read64;
map_banks[idx]->copy_to = bmc82xx_copy_to;
map_banks[idx]->virt = start_scan_addr;
map_banks[idx]->phys = flash_addr;
/* FIXME: This looks utterly bogus, but I'm trying to
preserve the behaviour of the original (shown
here)...
map_banks[idx]->map_priv_1 =
start_scan_addr + ((idx > 0) ?
(mtd_banks[idx-1] ? mtd_banks[idx-1]->size : 0)
: 0);
*/
if (idx && mtd_banks[idx-1]) {
map_banks[idx]->virt +=
mtd_banks[idx-1]->size;
map_banks[idx]->phys +=
mtd_banks[idx-1]->size;
}
//start to probe flash chips
mtd_banks[idx] = do_map_probe("cfi_probe", map_banks[idx]);
if (mtd_banks[idx]) {
mtd_banks[idx]->owner = THIS_MODULE;
mtd_size += mtd_banks[idx]->size;
num_banks++;
printk(KERN_INFO "%s: bank%d, name:%s,
size:%dbytes \n", __FUNCTION__, (int)num_banks,
mtd_banks[idx]->name,
(int)mtd_banks[idx]->size);
}
}
/* no supported flash chips found */
if (!num_banks) {
printk(KERN_NOTICE "TQM82xx: No support flash
chips found!\n");
ret = -ENXIO;
goto error_mem;
}#ifdef CONFIG_MTD_PARTITIONS
/*
* Select Static partition definitions
*/
part_banks[0].mtd_part = bmc82xx_partitions;
part_banks[0].type = "Static image";
part_banks[0].nums = ARRAY_SIZE(bmc82xx_partitions);
#if 0
part_banks[1].mtd_part = bmc82xx_fs_partitions;
part_banks[1].type = "Static file system";
part_banks[1].nums = ARRAY_SIZE(bmc82xx_fs_partitions);#endif
for(idx = 0; idx < num_banks ; idx++) {
if (part_banks[idx].nums == 0) {
printk(KERN_NOTICE "BMC flash%d: no
partition info available, registering whole flash at once\n", idx);
add_mtd_device(mtd_banks[idx]);
} else {
printk(KERN_NOTICE "BMC flash%d: Using
%s partition definition\n",
idx, part_banks[idx].type);
add_mtd_partitions(mtd_banks[idx], part_banks[idx].mtd_part,
part_banks[idx].nums);
}
}
#else
printk(KERN_NOTICE "BMC flash: registering %d whole
flash banks at once\n", num_banks);
for(idx = 0 ; idx < num_banks ; idx++)
add_mtd_device(mtd_banks[idx]);
#endif
return 0;
error_mem:
for(idx = 0 ; idx < FLASH_BANK_MAX ; idx++) {
if(map_banks[idx] != NULL) {
kfree(map_banks[idx]->name);
map_banks[idx]->name = NULL;
kfree(map_banks[idx]);
map_banks[idx] = NULL;
}
}
//error:
iounmap(start_scan_addr);
return ret;
}static void __exit cleanup_bmc_mtd(void)
{
unsigned int idx = 0;
for(idx = 0 ; idx < num_banks ; idx++) {
/* destroy mtd_info previously allocated */
if (mtd_banks[idx]) {
del_mtd_partitions(mtd_banks[idx]);
map_destroy(mtd_banks[idx]);
}
/* release map_info not used anymore */
kfree(map_banks[idx]->name);
kfree(map_banks[idx]);
}
if (start_scan_addr) {
iounmap(start_scan_addr);
start_scan_addr = 0;
}
}module_init(init_bmc_mtd);module_exit(cleanup_bmc_mtd);
MODULE_LICENSE("GPL");MODULE_AUTHOR("THEMIS COMPUTER "); MODULE_DESCRIPTION("MTD map driver for THEMIS BMC boards"); [bmc@Linux188 maps]$
___________________________________________________________________________ Faites de Yahoo! votre page d'accueil sur le web pour retrouver directement vos services préférés : vérifiez vos nouveaux mails, lancez vos recherches et suivez l'actualité en temps réel. Rendez-vous sur http://fr.yahoo.com/set